> 文档中心 > 身为阿里员工我竟不懂系统集成之服务集成交互技术:Linux I/O模式

身为阿里员工我竟不懂系统集成之服务集成交互技术:Linux I/O模式


Linux I/O模式

下图是根据同步、异步、阻塞、非阻塞四个指标总结的Linux下四个象限的I/O通信模式。

一般将网络消息是否有返回结果作为同步与异步的区分标准。

● 同步:应用程序要直接参与I/O读写操作,并等待消息响应结果。

● 异步:所有I/O读写交给操作系统去处理,不等待消息响应结果,程序只需要等待通知。阻塞与非阻塞是指应用I/O读写操作是否阻塞。

● 阻塞:往往需要等待缓冲区中的数据准备好后才处理其他的事情,否则一直等待。

● 非阻塞:当进程访问数据缓冲区时,如果数据没有准备好则直接返回,不会等待。如果数据已经准备好,也直接返回。

同步阻塞流程图如下。

同步阻塞对应的Linux API为recvfrom(Linux下的Socket接收数据函数)。下面我们以读操作为例看一下同步阻塞模式工作流程:

(1)进程发起读操作,进行recvfrom系统调用。

(2)内核开始进入准备数据(从磁盘复制到缓冲区)阶段,准备数据是要消耗一定时间的。

(3)与此同时,应用用户态进程阻塞,进入等待数据状态。

(4)数据从内核复制到用户空间,内核返回结果,进程解除阻塞。也就是说,内核准备数据和数据从内核复制到进程这两个过程都是阻塞的。

同步非阻塞流程图如下。

同步非阻塞对应的Linux API为recvfrom-noblocking。你可以通过设置Socket的初始化参数使其变为非阻塞状态。当对一个非阻塞状态的Socket执行读操作时,流程如下:

(1)用户进程发出读操作。

(2)如果内核中的数据还没有准备好,那么读操作并不会阻塞用户进程,而是立刻返回一个错误。从用户进程的角度来看,它发起一个读操作后不需要等待,马上就能得到返回结果。

(3)当用户进程再次发起读操作时,一旦内核中的数据准备好了,那么它马上就将数据复制到用户空间,然后返回。

非阻塞I/O的特点是用户进程在内核准备数据的阶段需要不断地主动询问数据好了没有。

异步阻塞流程图如下。

异步阻塞对应的Linux API为select、poll、epoll。异步阻塞其实就是我们经常提的I/O多路复用模式。epoll监听不同网络事件,当有事件通知时就通知用户进程。好处是单个进程可以处理多个Socket。现在看一下I/O多路复用的流程:

(1)当用户进程调用了select函数,那么整个进程会被阻塞。

( 2 ) 与 此 同 时 , 内 核 会 “ 监 视 ” 所 有 select 函 数 负 责 的Socket(网络文件句柄)。

(3)任何一个Socket中的数据准备好了,select函数就会返回。

(4)这个时候用户进程再调用读操作,将数据从内核复制到用户空间。

所以,I/O多路复用的特点是通过一种机制,使用一个单独的线程同时等待多个文件描述符,而这些文件描述符其中的任意一个Socket(套接字描述符)进入读/写就绪状态,select函数就可以返回。

异步非阻塞流程图如下。

异步非阻塞对应的Linux API为aio_read/aio_write,流程如下。

(1)用户进程发起读操作之后,立刻开始去做其他事情。

(2)从内核的角度看,当它收到一个异步读操作之后,首先它会立刻返回,不会对用户进程产生任何阻塞。

(3)内核会等待数据准备完成,然后将数据复制到用户空间,当这一切都完成之后,内核会给用户进程发送一个信号,通知用户读操作已完成。

总结一下,上述四种I/O模式都可以分为两个阶段:一个是数据准备阶段,另一个是内核与用户空间的数据复制阶段,如下图所示。

四种I/O模式的主要区别就是第一阶段,因为第二阶段都需要阻塞等待数据从内核复制到用户空间。只有“异步非阻塞”的第二阶段与其他三种I/O模式都不相同,它在这两个阶段都是通过操作系统的事件回调通知完成的。