redis自学(19)epoll事件通知机制

epoll事件通知机制

FD有数据可读时,我们调用epoll_wait就可以得到通知。但是事件通知的模式有两种:

  •  LevelTriggered:简称LT。当FD有数据可读时,会重复通知多次,直到数据处理完成。是epoll的默认模式。
  •  EdgeTriggered:简称ET。当FD有数据可读时,只会被通知一次,不管数据是否处理完成。

LT举个例子:

① 假设一个客户端socket对应的FD已经注册到了epoll实例中

② 客户端socket发送了2kb的数据

③ 服务端调用epoll_wait,得到通知说FD就绪

④ 服务端从FD读取了1kb数据

⑤ 回到步骤3(再次调用epoll_wait,形成循环)

ET的话,再次步骤3的时候,就不会通知就绪了。

内部实现差异:

调用epoll_wait的时候,list_head会断开与链表的连接,在链表拷贝到过用户态后,会判断是ET还是LTET的话,就不恢复连接了,那么list_head就会是空;而LT的话,如果链表里面还有数据,就会恢复连接。

ET如何解决数据读取问题?

第一种方式:手动LT,也就是说,断开连接拷贝完数据后,如果还有数据,就会调用epoll_ctl,判断哪些数据就绪了,然后再添加到list_head

第二种方式:在步骤4循环读取,全都读完为止(不能用阻塞IO的模式去读取,阻塞IO读完了不是返回错误,而是会等待,导致进程被阻塞;而非阻塞IO,有数据返回,没数据返回无数据的标识)

LT的问题:

重复通知对于效率和性能会有影响

LT可能会出现惊群的现象(在多线程的情况下,都在调用epoll_wait获取就绪的FD,而因为任何一个进程它通知完了一个,因为FD还在list_head里面,所以其他监听FD的进程都会被通知到,其实有可能就绪FD就被第一个或者第二个进程处理完了, 后续的进程没有必要被唤醒,而ET就没有这个情况)

结论:

  • ET模式避免了LT模式可能出现的惊群现象
  • ET模式最好结合非阻塞IO读取FD数据,相比LT会复杂一些(性能会更好一些)
posted @ 2024-03-15 15:43  蓝海的bug本  阅读(35)  评论(0编辑  收藏  举报