IO模型

发表信息: by

Unix五种可使用的I/O模型

Unix有五种可以使用的IO模型,分别是:

  • blocking io
  • nonblicking io
  • io multiplexing
  • signal driven io
  • asynchrous io

我们知道, 当有input操作的时候,会发生下面两种事情:

  1. 等待数据ready
  2. 把数据从内核copy到进程中

这个第一步通常是等待网络的数据到达, 当数据到达之后, 把数据复制到内核的缓冲区中; 第二部便是把数据从内核的缓冲区复制到应用缓冲区中。

Blocking I/O

阻塞IO,大多数的io模型都是这种, 所有的socket被阻塞,直到数据准备好。

我们使用UDP代替TCP举例子,因为UDP中数据ready是一个很简单的过程,TCP更复杂.

io-1

当进程要读取数据的请求时候, 便会阻塞在这, 直到数据准备好。这样会导致进程中其他的操作要等待这个IO操作完成。

Nonblocking I/O

io-1

上面这个流程是 非阻塞IO的模型, 当进程要进行数据读写的时候, 不被阻塞在此处, 内核会返回 一个标示来告诉进程, 此时内核正在准备数据, 请等一会再过来请求。 当内核把数据准备完成之后, 进程再次请求的时候便可以进行 “内核复制数据到应用缓存” 中啦。

I/O Multiplexing

io-1

IO多路复用模型,当应用程序请求数据的时候,进程将会调用Unix内核提供的Select或者Poll方法, 并且进程等待,直到有任何一个Select准备好数据。

Signal Driven I/O

io-1

信号驱动IO模型, 当进程请求数据的时候,向内核注册“准备数据”的信号,并且进程挂起,直到内核使用“准备数据”信号将进程唤醒, 接着进程开始将内核中的数据复制到应用缓冲区中,读取数据完成。

Asynchronous I/O

io-1

异步IO模型,当进程请求数据的时候,调用内核的接口,将要写入数据的目标地址也告诉内核, 这样进程就不再等待, 继续执行其他的事情。 内核接收到应用程序的异步请求,便自己运行,将数据准备好,并且将数据复制到进程指定的地方。

五种模型比较

在这五种模型中, 前四种都是同步IO的模型, 没错,前四种都是同步IO, 只有第五种是异步IO。

为什么这么说,因为前四种都在数据准备阶段进行 挂起/睡眠/等待。 他们都要等待内核准备好数据才回进行下面的操作

模型1同步阻塞IO和模型2同步非阻塞IO的区别比较明显,这里便不多做考虑, 我们看下3多路复用IO和4信号驱动IO各有什么好处。

我觉得多路复用IO最大的好处是不阻塞入口,因为这里涉及到内核poll和select函数,所以可能不太好理解, 我们拿Java多线程举例:

// thread 1
while (true) {
  request = server.accept();
  registrySelect(request);
}

// thread 2
while (true) {
  readyRequest = selectDataReady()
  dispose(readyRequest)
}

这里有两个线程, 线程1接收请求, 如果接收到请求后将请求注册到select中, select的作用就是查询是否有数据准备好的请求, 如果有便处理该请求。

第五个异步IO就不用说了。

参考资料

这里将多路复用还蛮清楚的 UNIX Network Programming, Volume 1, Third Edition, The Sockets Networking API 6.2 IO Models