epoll 使用 LT + 非阻塞 IO 和 ET + 非阻塞 IO 比较

  epoll默认的模式我们称为水平触发模式(Level Trigger,LT);与 poll 的事件宏相比,epoll 新增了两个事件宏 EPOLLET和EPOLLONESHOT,EPOLLET就是边缘触发模式(Edge Trigger,ET),当往epoll内核事件表中注册fd上的EPOLLET事件类型时,epoll将以ET模式操作该fd。

  对于水平触发模式,只要有事件,就会一直触发;对于边缘触发模式,只有一个事件从无到有才会触发。

可读事件水平模式触发条件:

  无数据 => 有数据
处于有数据状态

可读事件边缘模式触发条件:

  无数据 => 有数据
又新来一次数据

可写事件水平模式触发条件:

  不可写 => 可写
 处于可写状态

可写事件边缘模式触发条件:

  不可写 => 可写

 

处理读事件:

  对于fd的读事件,对于水平触发模式,只要fd上有未读完的数据,就会一直产生 POLLIN 事件。而对于边缘触发模式,只会触发且仅触发一次;如果上一次触发后,未将fd上的数据读完,也不会再触发,除非再新来一次数据

 

处理写事件:

  对于fd的写事件,对于水平触发模式,如果fd的 TCP 窗口一直不饱和,会一直触发 POLLOUT 事件。而对于边缘触发模式,只会触发且仅触发一次;如果上一次触发后,未将TCP窗口写饱和,也不会再触发,除非 TCP 窗口再一次由饱和变成不饱和。

  对于一个非阻塞fd,如果使用 epoll 边缘模式去检测fd是否可读,触发可读事件以后,一定要循环调用 recv 函数直到 recv 返回0,此时表示 fd上本次数据已经读完;如果使用水平模式,则不用,你可以根据业务一次性收取固定的字节数,或者收完为止。

  对于一个非阻塞fd,如果使用 epoll 边缘模式去检测fd是否可写,即使给 fd 注册了可写事件不会一直触发,只会触发一次,可写事件触发后,调用 send 函数去发送数据,如果数据本次不能全部发送完,一定要继续注册检测可写事件,否则你剩余的数据就再也没有机会发送了,因为 ET 模式的可写事件再也不会触发;如果使用水平触发模式,为了避免不必要的可写触发,浪费CPU资源,需要在数据发送完立即移除检测可写事件。

 

参考资料 https://mp.weixin.qq.com/s/k3qALmbjxxAPPg6v1-RDOA

    

 

posted @ 2021-04-13 23:21  封狼居胥!  阅读(321)  评论(0编辑  收藏  举报