1.epoll存在两种触发模式:水平触发(LT)和边缘触发(ET)
水平触发(LT):
- 关心的是缓冲区的状态,当缓冲区可读(即缓冲区中只要有数据)时,就会发出通知。
它是epoll默认的工作模式。 - 当被监控的文件描述符上有可读写事件发生时,`epoll_wait()`会通知处理函数去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用`epoll_wait()`时,它还会通知你在上次没读写完的文件描述符上继续读写,这种通知是持续的,只要没有把数据读写完。
- 优点:保证了数据的完整输出,即只要还有数据在缓冲区中,epoll_wait就会一直被触发,直到缓冲区为空。
- 缺点:当数据较大时,需要不断从用户态和内核态切换,消耗大量的系统资源,影响服务器性能。
- 应用场景:连接请求较少及客户端发送的数据量较少的服务器,可一次性接收所有数据。
边缘触发(ET):
- 关心的是缓冲区状态的变化,只有当缓冲区状态发生变化(例如有新的数据到达)时,才会发出通知。
- 是一种高效的工作模式,只支持无阻塞套接字(no-block socket)。
- 当被监控的文件描述符上有可读写事件发生时,`epoll_wait()`会通知处理函数去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用`epoll_wait()`时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件。(对于读事件 `EPOLLIN`,只有socket上的数据从无到有,`EPOLLIN` 才会触发;对于写事件 `EPOLLOUT`,只有在socket写缓冲区从不可写变为可写,`EPOLLOUT` 才会触发(刚刚添加事件完成调用epoll_wait时或者缓冲区从满到不满))
- 优点:每次内核只会通知一次,大大减少了内核资源的浪费,提高了效率。
- 缺点:不能保证数据的完整性,即不能确保及时取出所有的数据。
- 应用场景:处理大数据,与非阻塞IO一起使用(应该是非阻塞IO读的快一些吧)。在ET模式下,epoll_wait触发一次后,在循环内使用非阻塞IO读取数据,直到缓冲区数据为空,内核才会继续调用epoll_wait等待事件发生。
2.select和poll只支持水平触发(Level Triggered,简称LT)模式,而不支持边缘触发(Edge Triggered,简称ET)模式。