AnSwErYWJ's Blog

UNIX下IO模型分析

字数统计: 1.3k阅读时长: 25 min
2017/06/27

UNIX下的五种常见IO模型分析,帮助理解

IO操作的两个阶段

以读数据操作为例:

  1. 等待内核数据准备(数据拷贝到内核缓冲区)
  2. 将数据从内核拷贝到用户空间

IO模型

UNIX下共有五种常见的IO模型:
UNIX下共有五种常见的IO模型

下面以recvfrom接口举例

阻塞IO

默认情况下,所有的套接字都是阻塞的
阻塞IO
调用recvfrom接口,进程在IO操作的两个阶段都会阻塞,直到最终数据拷贝到用户空间或者过程中出现错误才会返回,进程在阻塞状态下是不占用CPU资源的

最常见的错误是发生系统中断,此时需要重读,可参考这里

非阻塞IO

可以通过fcntl(sockfd,F_SETFL,O_NONBLOCK)将套接字设置成非阻塞
非阻塞IO
调用recvfrom接口,无论内核缓冲区是否有可用数据,进程都会立即返回,所以在IO操作的第一阶段是非阻塞的; 若无数据可用,内核将errno设置为为EWOULDBLOCK或者EAGAIN,进程可以使用轮询的方法,保证内核在数据准备好时,能立即拷贝到用户空间; 若有则立即将数据拷贝到用户空间,进程在数据拷贝到用户空间即IO操作的第二阶段是阻塞的;

非阻塞IO过于消耗CPU时间,将大部分时间用于轮询

多路复用IO

多路复用系统调用:select,pollepoll,其中windows平台不支持pollepoll,使用方法可以参考I/O 多路复用之select、poll、epoll详解Linux select/poll和epoll实现机制对比
 多路复用IO
调用select,等待内核数据准备,所以IO操作的第一个阶段,进程是阻塞的,不过是阻塞在多路复用系统调用上,而不是IO系统调用上; 当select返回套接字可读条件时,再调用recvfrom将数据从内核拷贝到用户空间,IO操作的第二阶段,进程是阻塞的

多路复用IO和阻塞IO,在IO操作的两个阶段都是阻塞的,不过多路复用IO使用了两个系统调用,而阻塞IO只使用了一个,所以在连接数不是很多的情况下,阻塞IO可能性能更佳; 多路复用IO的优势在于可以同时监控多个用于IO的文件描述符。

多线程中的阻塞IO,与多路复用IO极为相似

信号驱动IO

信号驱动IO
调用sigaction等系统调用安装信号处理函数,并立即返回,所以IO操作的第一阶段,进程是非阻塞的; 当内核数据准备好时,内核会产生一个信号,通知进程将数据从内核拷贝到用户空间,IO操作的第二阶段,进程是阻塞的

使用方法:IO的多路复用和信号驱动

异步IO

异步IO有一组以aio开头的系统调用,使用方法可参考Linux AIO机制
异步IO
调用异步IO系统调用,给内核传递描述字、缓冲区指针、缓冲区大小(与read相同的三个参数)、文件偏移(与lseek类似),告诉内核当整个操作完成时如何通知我们,并立即返回,在IO操作的两个阶段,进程都不阻塞

总结

5种IO模式比较

  • 同步IO和异步IO的主要区别是将数据从内核拷贝到用户空间是否阻塞,前者会在将数据从内核拷贝到用户空间时即IO操作的第二个阶段发生阻塞,而后者则在系统调用后直接返回,直到内核发送信号通知IO操作完成,在IO操作的两个阶段都没有阻塞
  • 阻塞IO和非阻塞IO的主要区别是系统调用是否立即返回(默认将数据从内核拷贝到用户空间即IO操作的第二个阶段是立即返回的),前者会在IO操作的两个阶段完成前一直阻塞,后者在内核没有准备好数据的情况下立即返回,即只会在IO操作的第二个阶段阻塞
  • 信号驱动IO和异步IO的主要区别在于前者由内核通知我们何时启动一个IO操作,在将数据从内核拷贝到用户空间过程中即IO操作的第一个阶段依旧是阻塞的,而后者是由内核通知我们IO操作何时完成,在IO操作的两个阶段都没有阻塞

知乎上有一个比较生动的例子可以说明这几种模型之间的关系。

Reference

原文作者:AnSwErYWJ

原文链接:https://answerywj.com/2017/06/27/io-model/

发表日期:2017/06/27 16:06

版权声明:本文采用Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License进行许可.
Creative Commons License

CATALOG
  1. 1. IO操作的两个阶段
  2. 2. IO模型
    1. 2.1. 阻塞IO
    2. 2.2. 非阻塞IO
    3. 2.3. 多路复用IO
    4. 2.4. 信号驱动IO
    5. 2.5. 异步IO
  3. 3. 总结
  4. 4. Reference