多路复用I/O不管是select、poll还是epoll,都是同时监听多个fd,当有fd处于就绪状态时,就触发通知;
水平触发(LT,Level Trigger)和边沿触发(Edge Trigger)模式是两种fd准备就绪的通知模式
水平触发
- 只要文件描述符关联的读内核缓冲区非空,有数据可以读取,就一直发出可读信号进行通知
当文件描述符关联的内核写缓冲区不满,有空间可以写入,就一直发出可写信号进行通知
边沿触发
当文件描述符关联的读内核缓冲区由空转化成非空的时候,则发出可读信号进行通知
- 当文件描述符关联的内核写缓冲区由满转化为不满时,则发出可写信号进行通知
区别
水平触发只要是读缓存区有数据,就会一直触发可读信号,而边沿触发仅仅在空变为非空的时候通知一次,例如:
- 读缓冲区刚开始是空的
- 读缓冲区写入2KB数据
- 水平触发和边沿触发模式此时都会发出可读信号
- 收到信号通知后,读取了1KB的数据,读缓冲区还剩余1KB数据
- 水平触发还会再次发出通知,而边沿触发不会通知
所以ET需要一次性的把缓冲区的数据读完为止,依旧是一直读,直到读到EAGIN(表示缓冲区已经为空)。所以ET需要设置文件句柄为非阻塞。
ET模式在很大程度上减少了epoll事件被重复触发的次数,因此效率比LT模式要高。 epoll工作在ET模式时,必须要使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个fd的任务饿死。
| I/O模式 | 水平触发 | 边沿触发 |
|---|---|---|
| select() | 支持 | 不支持 |
| poll() | 支持 | 不支持 |
| epoll() | 支持 | 支持 |
select和poll只支持LT工作模式,epoll的默认的工作模式是LT模式,当往epoll内核事件表中注册一个文件描述符上的EPOLLET事件时,epoll将以ET模式来操作该文件描述符。
