本文是对阻塞、非阻塞、同步、异步、I/O多路复用的总结。

1 阻塞 I/O(blocking IO)


blocking IO的特点就是在IO执行的两个阶段都被block了。

2 非阻塞 I/O(nonblocking IO)


nonblocking IO的特点是用户进程需要不断的主动询问kernel数据好了没有。

3 I/O 多路复用( I/O multiplexing)


I/O multiplexing本质上是多条I/O路径共用同一个线程。
详情可以参考select, poll, and epoll

4 异步 I/O(asynchronous IO)


异步I/O通知可以采取两种方式:

  1. 使用信号进行异步通知,如上图所示,示例可以参考POSIX Asynchronous I/O
  2. 使用回调函数进行异步通知,示例可以参考linux下aio异步读写详解与实例UNIX/Linux signal handling: SIGEV_THREAD

5 总结

5.1 blocking和non-blocking的区别

调用blocking IO会一直block住对应的进程,直到操作完成;而non-blocking IO在kernel还未准备好数据的情况下会立刻返回。

5.2 synchronous IO和asynchronous IO的区别

在说明synchronous IO和asynchronous IO的区别之前,需要先给出两者的定义。POSIX的定义是这样子的:

  • A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes;
  • An asynchronous I/O operation does not cause the requesting process to be blocked;

两者的区别就在于synchronous IO做”IO operation”的时候会将process阻塞。按照这个定义,之前所述的blocking IO,non-blocking IO,IO multiplexing都属于synchronous IO。

有人会说,non-blocking IO并没有被block啊。这里有个非常“狡猾”的地方,定义中所指的”IO operation”是指真实的IO操作,就是例子中的read这个system call。non-blocking IO在执行read这个system call的时候,如果kernel的数据没有准备好,这时候不会block进程。但是,当kernel中数据准备好的时候,read会将数据从kernel拷贝到用户内存中,这个时候进程是被block了,在这段时间内,进程是被block的。

而asynchronous IO则不一样,当进程发起IO 操作之后,就直接返回再也不理睬了,直到kernel发送一个信号,告诉进程说IO完成。在这整个过程中,进程完全没有被block。

5.3 各个IO Model的比较


通过上面的图片,可以发现non-blocking IO和asynchronous IO的区别还是很明显的。在non-blocking IO中,虽然进程大部分时间都不会被block,但是它仍然要求进程去主动的check,并且当数据准备完成以后,也需要进程主动的再次调用read来将数据拷贝到用户内存。而asynchronous IO则完全不同。它就像是用户进程将整个IO操作交给了他人(kernel)完成,然后他人做完后发信号通知或者调用回调函数。在此期间,用户进程不需要去检查IO操作的状态,也不需要主动的去拷贝数据。


参考资料:

  1. Linux IO模式及 select、poll、epoll详解
  2. select, poll, and epoll
  3. Asynchronous I/O and event notification on linux
  4. Asynchronous File I/O on Linux
  5. linux下aio异步读写详解与实例
  6. aio (7) - Linux Man Pages
  7. UNIX/Linux signal handling: SIGEV_THREAD
  8. POSIX Asynchronous I/O