IO复用\阻塞IO\非阻塞IO\同步IO\异步IO

 本文是对《UNIX网络编程卷1》第6章的总结。 编程

1、            什么是IO复用? 缓存

它是内核提供的一种同时监控多个文件描述符状态改变的一种能力;例如当进程须要操做多个IO相关描述符时(例如服务器程序要同时查看监听socket和大量业务socket是否有数据到来),须要内核可以监控这许多描述符,一旦这些描述符有就绪(或者状态改变了)就告诉主动告诉进程哪些描述符已经就绪,这样站在进程的角度,就不须要挨个的查看每一个描述符是否就绪。 服务器

2、            IO操做分为两个阶段: 网络

(1)      准备阶段,例如输入操做时要等待数据已经就绪,输出操做时缓冲区中有空间可供使用; 异步

(2)      数据拷贝阶段,例如输入操做时将数据从内核复制到用户缓存,输出操做时将用户缓存复制到内核。 socket

以读取系统调用recvfromfrom为例,每当用户进程发起一个recvfrom操做,站在用户进程的角度,其实它包含上述两个请求:第一个请求就是看看数据是否是准备好了,若是没有准备好就把我阻塞那里(对应阻塞IO)或者给我返回个没有准备好的标志(对应非阻塞IO);第二个请求就是在数据就绪的时候将数据拷贝给用户进程。 函数

 

3、            Unix环境下有5中IO模型 spa

(1)阻塞IO模型 .net

(2)非阻塞IO模型 blog

(3)IO复用模型

(4)信号驱动IO模型

(5)异步IO模型

其中(1)~(4)都属于同步IO,(5)属于异步IO,由于前4中模型在第一阶段的准备阶段有区别,在第二阶段的数据拷贝过程当中都会阻塞用户进程,而(5)在第一阶段的准备阶段和第二阶段的数据拷贝过程都不会阻塞用户进程。

4、            各类模型的详细区别

(1)      阻塞IO模型

阻塞IO模型中,以数据接收为例,进程调用recvfrom系统调用向内核请求读取数据,其内部过程将以下图1所示:


图1阻塞IO模型

由图1能够看到用户进程从发起recvfrom系统调用开始后的两个阶段都被阻塞。

(2)      非阻塞IO模型

以读取数据为例,非阻塞模型中,进程须要先把socket设置为非阻塞模式,这样内核在准备数据时就不会阻塞该系统调用,而是直接返回EWOULDBLOCK,在读取操做时,用户进程同样是调用recvfrom向内核请求数据,其内部过程以下图2所示:


图2 非阻塞模式IO模型

由上图2能够看到非阻塞模式中,在数据准备阶段,系统调用不会被阻塞,可是在数据复制阶段也会被阻塞;所以这里所说的阻塞是指数据准备阶段是否被阻塞,而不是数据拷贝阶段。

(3)      IO复用模型

IO复用模型中,进程可让内核监控多个描述符的就绪状态,通常使用的接口函数为select或者poll,内核经过select查询到所监控的描述符中有就绪的,则把就绪的描述符返回给调用进程,进程再调用recvfrom实际读取数据,其内部过程大体以下图3所示:


图3 、IO复用模型

由上图能够看出,在IO复用模型中,用户进程先调用select或者poll查看是否有数据就绪,若是有数据就绪再调用recvfrom去读取数据,系统在阶段1和阶段2都将会被阻塞,可是阻塞于不一样的系统调用(阶段1阻塞于select或者poll,阶段2阻塞于recvfrom)。

(4)      信号驱动IO模型

信号驱动IO模型是让内核在描述符就绪时发送SIGIO信号通知用户进程。在使用信号驱动模型进行IO操做时,首先要打开socket使用信号驱动IO的能力;而后调用sigaction系统调用设置信号SIGIO的处理函数,sigaction系统调用不会被阻塞。这样就能够在信号处理函数中读取数据了,其处理过程以下图4所示:


图4 信号驱动IO模型

由上图4能够看出,信号驱动模型只要设置好信号处理函数后就能够进行其余操做了,当有数据到来时内核将会通知进程进行处理;与非阻塞IO模型相比,信号驱动IO模型不须要在准备数据时轮询是否准备好。

(5)      异步IO模型

异步IO模型中,用户进程发起读取调用以后会当即返回,待内核接收到数据并将数据拷贝到用户进程空间以后,再通知用户进程,其过程以下图5所示:


图5异步IO模型

5、5中IO模型的比较

上述5中IO操做模型的区别能够参见图6所示:


图六、5中IO模型的比较

同步IO:致使请求进程阻塞,直到IO操做完成;

异步IO:不致使请求阻塞;

所以,前面介绍的5中模型中,前4中IO模型都属于同步IO,由于他们第二阶段的复制数据过程将阻塞用户进程,只有第5种才是真正的异步IO模型。