Linux企业实战-漫谈5种io模型

1.IO 简述

IO (Input/Output,输入/输出)即数据的读取(接收)或写入(发送)操作,通常用户进程中的一个完整IO分为两阶段:用户进程空间<–>内核空间、内核空间<–>设备空间(磁盘、网络等)。
Linux企业实战-漫谈5种io模型
IO有内存IO、网络IO和磁盘IO三种,通常我们说的IO指的是后两者。

LINUX中进程无法直接操作I/O设备,其必须通过系统调用请求kernel来协助完成I/O动作;内核会为每个I/O设备维护一个缓冲区。

对于一个输入(读取到内存)操作来说,进程IO系统调用后,内核会先看缓冲区中有没有相应的缓存数据,没有的话再到设备中读取,因为设备IO一般速度较慢,需要等待;内核缓冲区有数据则直接复制到进程空间。

所以,对于一个网络输入(读取网络资源)的操作,通常包括两个部分

(1)等待网络数据到达网卡 --> 读取到内核空间 (这个过程就是准备数据)
(2)从内核缓冲区复制数据到进程空间,然后具体的用户函数,把结果返回。

IO 操作发生时一般涉及两个对象,一个是调用这个IO的 process (or thread) ,另一个就是系统内核 (kernel)

2.IO 模型介绍

一共有五种 IO 模型
(1)阻塞 IO
(2)非阻塞 IO
(3)多路复用 IO
(4)信号驱动 IO
(5)异步 IO
其中,前面4种是同步IO,最后一个是异步IO
(1)阻塞 IO
阻塞I/O模型示意图:
Linux企业实战-漫谈5种io模型
进程发起IO系统调用后,进程被阻塞,转到内核空间处理,整个l0处理完毕后返回进程。操作成功则进程获取到数据小明去火车站买票,排队三天买到一张退票。耗费:在车站吃喝拉撒睡3天,其他事一件没干
(2)非阻塞 IO
Linux企业实战-漫谈5种io模型
进程发起IO系统调用后,如果内核缓冲区没有数据,需要到I0设备中读取,进程返回一个错误而不会被阻塞;进程发起I0系统调用后,如果内核缓冲区有数据,内核就会把数据返回进程。
对上面的阻塞l0模型来说,内核数据没准备好需要进程阻塞的时候,就返回一个错误,以使得进程不被阻塞小明去火车站买票,隔12小时去火车站问有没有退票,三天后买到一张票。耗费:往返车站6次,路上6小时,其他时间做了好多事
(3)多路复用 IO
Linux企业实战-漫谈5种io模型
**多个的进程的I0可以注册到一个复用器(select)上,然后用一个进程调用该select,select会监听所有注册进来的lO;
如果select没有监听的I0在内核缓冲区都没有可读数据,select调用进程会被阻塞;而当任一I0在内核缓冲区中有可数据时,select调用就会返回;
而后select调用进程可以自己或通知另外的进程(注册进程)来再次发起读取lO,读取内核中准备好的数据典型应用:select、poll、epoll三种方案,nginx都可以选择使用这三个方案

select、poll、epollLinux中l0复用的实现方式主要有
select、poll和epoll:
Select:注lO、阻塞扫描,监听的IO最大连接数不能多于FD_SIZE;
Poll:原理和Select相似,没有数量限制,但IO数量大扫描线性性能下降;
Epoll:事件驱动不阻塞,mmap实现内核与用户空间的消息传递,数量很大,Linux2.6后内核支持

1.select/poll
小明去火车站买票,委托黄牛,黄牛三天内买到票,然后打便所有人要买票人的电话找到小明,小明去火车站交钱领票。T
耗费:往返车站2次,路上2小时,黄牛手续费100元,等待通知3小时
2.epoll
小明去火车站买票,委托黄牛,黄牛买到后即通知小明去领,然后小明去火车站交钱领票。
耗费:往返车站2次,路上2小时,黄牛手续费100元,无需打电话

(4)信号驱动 IO
Linux企业实战-漫谈5种io模型
当进程发起一个l0操作,会向内核注册一个信号处理函数,然后进程返回不阻塞;当内核数据就绪时会发送一个信号给进程,进程便在信号处理函数中调用IO读取数据小明去火车站买票,给售票员留下电话,有票后,售票员电话通知小明,然后小明去火车站交钱领票。
耗费:往返车站2次,路上2小时,免黄牛费100元,无需打电话
Linux企业实战-漫谈5种io模型
当进程发起一个lO操作,进程返回(不阻塞),但也不能返回果结;内核把整个IO处理完后,会通知进程结果。如果I0操作成功则进程直接获取到数据

小明去火车站买票,给售票员留下电话,有票后,售票员电话通知小明并快递送票上门。
耗费:往返车站1次,路上1小时,免黄牛费100元,无需打电话

(5)异步 IO模型
Linux企业实战-漫谈5种io模型
用户进程发起aio_read(POSIX异步IO函数aio_或者lio_开头)操作之后、给内核传递描述符、缓冲区指针、缓冲区大小和read相同的三个参数以及文件偏移(与lseek类似)、告诉内核当整个操作完成时、如何通知我们、立刻就可以开始去做其它的事、而另一方面、从内核的角度、当它受到一个aio_read之后、首先它会立刻返回、所以不会对用户进程产生任何阻塞、然后、内核会等待数据准备完成、然后将数据拷贝到用户内存、当这一切都完成之后、内核会给用户进程发送一个信号、告诉它aio_read操作完成了

通俗的举例就是:
老李去火车站买票,给售票员留下电话,有票后,售票员电话通知老李并快递送票上门。
耗费:往返车站1次,路上1小时,免黄牛费100元,无需打电话

异步IO的工作机制是:告知内核启动某个操作、并让内核在整个操作完成后通知我们、这种模型与信号驱动的IO区别在于、信号驱动IO是由内核通知我们何时可以启动一个IO操作、这个IO操作由用户自定义的信号函数来实现、而异步IO模型是由内核告知我们IO操作何时完成、

在异步IO模型中、真正实现了POSIX描述的异步IO、是五种IO模型中唯一的异步模型
典型应用:Java 7 AIO、高性能服务器应用不阻塞、数据一步到位、Proactor模式需要操作系统的底层支持、LINUX 2.5 版本内核首现、2.6 版本产品的内核标准特性
回调机制、实现、开发应用难度大非常适合高性能高并发应用