在 Linux 的 epoll
中,主要有两种触发模式:水平触发(Level Triggered, LT) 和 边缘触发(Edge Triggered, ET)。它们的行为有较大的区别:
水平触发(LT)
-
基本原理:
当文件描述符处于“可读”或“可写”的状态(即缓冲区中有数据,或有缓冲区可用于写入)时,只要进入epoll_wait
就总是返回这个文件描述符,无论你在之前是否已经处理过这些数据。 -
优点:
编程较简单,不必担心一次未处理完数据时无法再次收到通知的问题。
数据未处理完毕的话,下一次epoll_wait
调用仍会收到事件。 -
缺点:
可能会频繁通知,导致重复处理同一事件(需要设计合适的处理逻辑)。
边缘触发(ET)
-
基本原理:
ET 模式只在状态发生变化时触发,例如从无数据到有数据,从不可写到可写。
如果数据到达后,你没有将缓冲区中的所有数据全部读取,ET 模式不会再次通知;同理,对于写操作,也需确保一次性写完或者正确处理 EAGAIN 的情况。 -
特点:
高效:减少重复的事件通知,特别适合高并发场景。
责任在用户:需要采用循环不断读取或写入直到返回EAGAIN
,确保所有数据处理完毕,防止数据“遗留”在缓冲区中后却没有再收到进一步的通知。 -
注意事项:
如果不注意循环读取/写入,很可能会导致部分数据没有处理而陷入阻塞状态,因为没有新的状态变化来生成新的事件通知。
总结
- LT 模式:只要缓冲区有数据,每次调用
epoll_wait
都会返回该文件描述符(只要它仍处于可读/可写状态)。 - ET 模式:只在状态从不可用变为可用时触发通知,例如数据刚刚到达;如果数据一次没有读取干净,程序必须遍历读取到
EAGAIN
,否则不会再次收到事件。
正确选择和使用这两种模式需要根据应用场景考虑:
- 如果希望简单且容错性较强,可以选择 LT 模式;
- 如果追求性能,并且能够保证一次性处理完所有数据,那么可以选择 ET 模式。