AE eventloop

2021-02-28  本文已影响0人  Spicy_Chicken

阅读浏览器源码的好工具:SourceGraph

Redis通过将对应事件注册到eventloop中,然后不断循环检测有无事件触发。

循环检测
aeProcessEvents代表处理一次循环事件处理:
  1. 取出最近的一次定时器事件。
  2. 计算该超时定时事件还有多久才可以触发,若已超时则设置t为0,其中t为第3步的超时阈值。
  3. 调用select或者epoll等待网络事件触发,或者超时。
  4. 处理触发的各个事件,包括网络事件和超时事件。

也就是说每次循环事件处理中,网络IO读写事件的处理过程中,会顺便检测处理定时事件。

关于第2点的额外说明,每次事件循环处理周期当中,获取距离当前的这个时间间隔值。拿来做什么用呢?

为了避免“忙等待”,我们在检查FD的IO读写状态时(select或者epoll),都会采用阻塞的方式,如果没有可读可写的FD,就一直阻塞着等待。但是,我还有定时器事件要处理啊,如果一直没有IO事件,那我定时器事件不是一直没法处理么?所以,我们会给select或者epoll传入一个阻塞的超时时间,超过这个时间,都给我返回。 下面获取的这个值,就是用于设置阻塞超时时间的。这样做,既可以避免非阻塞式的忙等待,又可以保证定时器事件能够按时得到处理。 其实这种处理方式非常普遍,以C为开发语言的很多服务型软件都是这样玩的。

Redis初始化服务的时候,会先初始化一个Eventloop

server.el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR); 
EventLoop数据结构
目前eventloop支持注册:

其中网络IO读写事件的fd看做下标的原因是:Linux内核会给每个进程维护一个文件描述符表。
而POSIX标准对于文件描述符进行了以下约束:

  1. fd为0、1、2分别表示标准输入、标准输出和错误输出。
  2. 每次新打开的fd,必须使用当前进程中最小可用的文件描述符。

因此注册事件下标能与系统fd形成有效重合复用。

其中我们关注的网络IO事件数据结构如下: 网络IO读写事件

一般情况下,Redis会先处理读事件(AE_READABLE),再处理写事件(AE_WRITABLE)。 这个顺序安排其实也算是一点小优化,先读后写可以让一个请求的处理和回包都是在同一次循环里面,使得请求可以尽快地回包。



网络IO事件注册的时候,除了正常的读写事件外,还可以注册一个AE_BARRIER事件,这个事件就是会影响到先读后写的处理顺序。 如果某个fd的mask包含AE_BARRIER,那它的处理顺序会是先写后读。


上一篇 下一篇

猜你喜欢

热点阅读