PythonIO多路复用

I/O多路复用

I/O模型

此处所讲的I/O模型是参考Richard Stevens所著《UNIX网络编程 卷1:套接字联网API》(第3版)中的I/O模型为基础。列举了其中所讲的5中I/O网络模型并加以描述对比。

网络I/O发生时系统涉及的操作

  • 数据准备(等待数据通过网络送达)
  • 将数据从内核复制到程序进程

阻塞I/O(blocking I/O)

  • 【Step 1】应用进程执行系统调用,阻塞直至数据准备完成
  • 【Step 2】将数据从内核复制到用户空间
  • 【Step 3】数据复制完成,返回成功指示,应用程序进程处理数据

非阻塞I/O(non-blocking I/O)

  • 【Step 1】应用进程执行系统调用,内核如果没有准备好数据不会阻塞,而是会以非阻塞方式返回错误码告知应用进程
  • 【Step 2】应用进程收到错误码后依然会不断系统调用询问内核是否准备好数据,直至内核准备好数据,返回成功
  • 【Step 3】将数据从内核复制到用户空间
  • 【Step 4】数据复制完成,返回成功指示,应用程序进程处理数据

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

类似于非阻塞I/O的轮询系统调用方式,区别在于轮询的执行不是由用户线程调用,而是内核调用

  • 【Step 1】应用进程执行系统调用,内核如果没有准备好数据不会阻塞,而是会以非阻塞方式返回错误码告知应用进程
  • 【Step 2】内核以轮询方式不断检查是否准备好数据,直至数据准备完成,返回成功
  • 【Step 3】将数据从内核复制到用户空间
  • 【Step 4】数据复制完成,返回成功指示,应用程序进程处理数据

信号驱动I/O(signal driven I/O)

使用信号,内核在数据准备就绪时通过信号来进行通知

  • 【Step 1】建立SIGIO的信号处理程序进行系统调用
  • 【Step 2】内核准备好数据后通过递交SIGIO告知应用进程
  • 【Step 3】将数据从内核复制到用户空间
  • 【Step 4】数据复制完成,返回成功指示,应用程序进程处理数据

异步I/O(Asynchronous I/O)

异步I/O通过信号处理程序告知应用进程,其告知应用进程的是I/O操作完成,而不是数据准备完成

  • 【Step 1】应用进程进行系统调用,内核通过非阻塞方式返回给应用程序
  • 【Step 2】当数据准备好时内核将数据复制到用户空间
  • 【Step 3】数据复制完成,递交再aio_read中指定的信号,应用程序进程处理数据

I/O模型比较分析

  • 阻塞I/O、非阻塞I/O、多路复用I/O、信号驱动I/O的相同点在于数据准备期间与数据从内核复制到用户空间这段过程中,都是阻塞状态。即上述这四种I/O模型都是同步I/O模型。
  • 异步I/O操作不会讲进程阻塞。


I/O多路复用的机制【TODO】

Select

线性扫描所有监听的文件描述符,不管他们是不是活跃的。有最大数量限制(32位系统1024,64位系统2048)

Poll

同select,不过数据结构不同,需要分配一个pollfd结构数组,维护在内核中。它没有大小限制,不过需要很多复制操作

Epoll

用于代替poll和select,没有大小限制。使用一个文件描述符管理多个文件描述符,使用红黑树存储。同时用事件驱动代替了轮询。epoll_ctl中注册的文件描述符在事件触发的时候会通过回调机制激活该文件描述符。epoll_wait便会收到通知。最后,epoll还采用了mmap虚拟内存映射技术减少用户态和内核态数据传输的开销