IO模型分析

本文主要讲的是网络IO技术,在网络IO中常见模型有五种BIONIOAIOI/O multiplexingSignal driven I/O,分别对应的是阻塞IO,非阻塞IO,异步IO,IO多路复用,信号驱动IO。本文主要讲述阻塞IO与三种IO多路复用

BIO

常见阻塞式IO即一个线程对应一个IO处理,当IO事件阻塞时,当前线程也一起阻塞,直到IO事件就绪。这种IO效率较为低下,在等待IO就绪期间线程一直处于阻塞状态,线程利用率低。此种IO模型除开初学者进行多线程IO训练,使用较少。

Select

select属于NIO的一种,属于非阻塞式IO,无需实现多个线程等待多个IO事件的就绪,select会维护一个名叫fd_set的事件描述符数组。

每一次需要发起IO请求时,就加入一个事件描述符到管道中,然后由select函数进行管道的遍历,不断的轮询管道中各个IO事件的状态,当出现某个IO事件状态为就绪时,就进行此IO事件的处理,这样多个线程的IO阻塞模型转换为IO的多路复用,也就是只需阻塞一个线程,监听管道描述符的IO事件状态,当有就绪事件时并进行处理,减少了IO事件未就绪时线程等待的开销,极大的提高了系统的性能。

Poll

poll函数为select函数的升级版,在select函数中维护了事件描述符数组,然而数组必须规定数组长度,无法像链表一样实现可增长。因此poll函数在用户态维护了描述符数组,在内核态处理IO操作时,将其转换为链表,这样就摆脱了最大文件描述符数量的限制。但是pollselect中内核态与用户态的拷贝带来性能损失问题始终没有解决。

Epoll

epoll是一种更为高效的多路复用技术,也是Nginx服务器能处理高流量背后的技术支撑他最大的特点就是解决了selectpoll中描述符序列中携带未就绪序列导致浪费的问题。他直接将描述符序列插入到内核中的epoll_event的红黑树描述符序列中,选择红黑树的原因是由于描述符序列需要频繁的查找,插入,删除,红黑树是最好的选择。

红黑树是一种自平衡二叉查找树,具有以下优点:

  1. 任何一个节点的左右子树的高度差不超过一倍。
  2. 查找、插入、删除操作的时间复杂度都是 $O(log n)$。
  3. 它能够快速地支持区间查找和排序等操作。

内核对红黑树中文件描述符进行监听,在使用 epoll_wait 等待事件时,可以指定一个回调函数,该函数将在事件到达时被调用,当事件触发后,内核会调用该回调进行操作。

epoll中水平触发和垂直触发

水平触发

当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件。下次调用epoll_ wait 时,会再次响应应用程序并通知此事件。

边缘触发

当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用epoll_ wait 时,不会再次响应应用程序并通知此事件。例如这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你。