本文共 2766 字,大约阅读时间需要 9 分钟。
本篇博文主要介绍UNIX中五种I/O模型。主要参考了UNP和
UNIX中的I/O模型分为一下五种:
对于任意一个I/O读取(input)操作,主要分为两个阶段:
1. 等待数据准备就绪(Waiting for the data to be ready) 2. 将准备好的数据从内核拷贝到用户缓冲(Copying the data from the kernel to the process)在网络编程中, 第一个阶段经常会使得读取进程进入等待状态,当数据就绪时,就会被拷贝到内核缓冲中。这两个阶段是理解后面关于非阻塞和异步的关键。
blocking IO
目前用的比较多的是阻塞I/O模型。默认情况下,所有的socket都是阻塞的。我们用下图来解释阻塞I/O模型:
当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据。对于network io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候kernel就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。当kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态,重新运行起来。
所以,blocking IO的特点就是在IO执行的两个阶段都被block了。nonblocking IO
linux下,可以通过设置socket使其变为non-blocking。当对一个non-blocking socket执行读操作时,流程是这个样子:
I/O multiplexing
I/O复用可以实现用一个进程监听多个套接口。主要的系统调用包括select和poll,但是由于他们的伸缩性不太好,现在用的比较多的是epoll。在监听多个套接口时,当任何一个套接口有数据可读,则会返回。从下面的示意图我们可以看到
Asynchronous I/O
我们通过调用aio_read来进行异步读操作。同时向内核传递套接口描述符,应用缓冲指针,缓冲大小和读取成功时,如何通知进程等参数。下面是示意图:
signal I/O
几种IO模型的比较
从这个模型的比较中,我们可以看出:blocking IO,nonblock IO, IO multiplexing,signal IO 这四种IO都是有阻塞的,并且他们的第二个阶段都是阻塞的。只是他们阻塞的阶段不同。但是异步IO是两个阶段都并不阻塞的。
同步I/O VS 异步 I/O
从UNP给出的定义中我们可以看到,同步的意思是:I/O操作会引起阻塞。这里的I/O操作是指两阶段中的第二个阶段(actual I/O operation),毕竟第一个阶段只是等待数据准备而已。
所以我们可以得出结论,blocking IO,nonblock IO, IO multiplexing,signal IO 这四种IO都是属于同步的。
最后,再举几个不是很恰当的例子来说明这四个IO Model(blocking ,nonnlocking, IO multilexing,异步IO): 有A,B,C,D四个人在钓鱼: A用的是最老式的鱼竿,所以呢,得一直守着,等到鱼上钩了再拉杆; B的鱼竿有个功能,能够显示是否有鱼上钩,所以呢,B就和旁边的MM聊天,隔会再看看有没有鱼上钩,有的话就迅速拉杆; C用的鱼竿和B差不多,但他想了一个好办法,就是同时放好几根鱼竿,然后守在旁边,一旦有显示说鱼上钩了,它就将对应的鱼竿拉起来; D是个有钱人,干脆雇了一个人帮他钓鱼,一旦那个人把鱼钓上来了,就给D发个短信。
这里第一阶段就是等鱼上钩,第二阶段就是把鱼钩拉起来。,将鱼钩拉上来才是 actual I/O operation,而在这个动作上,前面三个都是要阻塞的,所以前三种都是同步的模型。