epoll 的 et 和 lt

本文来自:Linux那些破事儿之我的高性能

但凡对epoll有一点点了解的人,都听说过epoll有两种工作模式,即ET(Edge Trigger)和LT(Level Trigger)模式。这两种工作模式的中文翻译分别是边沿触发和电平触发,还可以称为事件触发条件触发。我倒是觉得后者的翻译更能清楚的描述这两种工作模式的特点和差别。

当epoll工作在LT模式下,只要其监控的I/O句柄具备调用者所要捕获的条件——一般是可读或可写——就会通知给调用者。如果调用者不理会这个通知,它将一直通知下去,直到这个状态发生变化。当采用多进程模式(后面会详细介绍)编写服务器软件时,根据系统任务调度特性,采用LT模式可以使得所有连接均匀的分布于每个用于处理网络请求的进程。有汽车驾驶经验的童鞋可以将LT模式理解为驾驶自动档的汽车,只要设置好你感兴趣的I/O句柄和事件类型,在具备条件的时候epoll就会通知你,只需要做相关的处理就可以了,非常轻松惬意,代价就是稍微多出的那么一点点油耗。

当epoll工作在ET模式下,情况有些变得复杂了。原因就是这种基于事件的通知是事件发生后,只会产生一次通知。如果你不去理会它,它也不会再理会你,直到下一次事件发生。这会导致一个严重的后果就是当一个编写不够良好的程序,在获得事件通知后并没有将缓冲区的数据全部读取干净,epoll也不会有任何通知,没有读取到数据可能永远都不会被读取,或者使得那部分数据超时。另外,ET模式只允许非阻塞式I/O,这就进一步加剧了上述问题的恶化。解决的方法就是反复读取缓冲区,直到返回错误。所以,如果说LT模式是自动挡,那么ET模式就是手动挡,所有情况都得自己处理,处理不好就可能熄火,好处就是经济实惠。另外,ET模式在多进程服务器软件中,会导致连接在处理进程之间的不均匀分布,不过也只是相对的,当发现问题严重时,可适当暂停某个进程做接受新连接的处理。

答案就是:如果要发送数据,大多数直接调用send或wirte就可以了,直到他们返回EAGAIN错误,才需要将它们交给epoll去监控。一旦epoll_wait返回某个被监控的I/O句柄可写,则应该立即利用epoll_ctl将它删除,直到下次再出现EAGAIN错误。不过虽然说起来简单,但是真正到具体的操作还是比较麻烦。要完整可靠的发送数据:必须记录每次实际发送的数据量来统计剩余量;当发生EAGAIN错误后,必须将剩余的数据保存在一个地方,一般放在epoll_event结构的data字段中即可;当epoll通知可写后,将剩余数据发送出去;但是当遇到压力较大时,可能在发送剩余数据的时候还会发生EAGAIN错误,必须始终记录剩余数据才行。



Related posts(相关文章):
This entry was posted in 系统编程. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">