AE事件库
AE事件库是Redis作者自己写的一个轻型的异步网络库,不同于Libevent的臃肿,ae保持着它的轻量高效的特点。
Reactor模式
说到异步就不能不说说Reactor模式,这是广泛应用的一种服务端开发模式,它本着don't call us,we will call you的思想,将同步阻塞的代码变成了基于事件回调的模式。
准确的说就是有一个不断循环的线程,这个线程会不断的轮询发生的事件,然后挨个处理所发生的事件,调用事件事先注册好的回调函数,这个线程就被称作Reactor。
AE底层实现
ae的实现根据操作系统的不同会采用最高效的I/O多路复用机制:
/* Include the best multiplexing layer supported by this system.
* The following should be ordered by performances, descending. */
#ifdef HAVE_EPOLL
#include "ae_epoll.c"
#else
#ifdef HAVE_KQUEUE
#include "ae_kqueue.c"
#else
#include "ae_select.c"
#endif
#endif
可以看到AE优先使用epoll>kqueue>select的顺序去选择I/O多路复用的底层实现。
AE主要包括的几个部分
EventLoop
事件循环,这不仅是AE,也是Redis最重要的一个部分。它是一个结构体,里面保存着事件循环总体的信息,比如:
时间事件的链表头,最大的文件描述符,sleep前要执行的任务函数等。
事件
AE中事件分为文件事件和时间事件两种,对于文件事件来说就是调用多路复用函数去收集到的发生的事件,对于每个文件事件,又分为读事件和写事件两种,分别调用对应的回调函数去处理他们。
而时间事件在eventLoop中以一个链表的形式存在,在调用多路复用函数的时候,AE会去查询最近的一个时间事件,并用它的发生时间-当前时间的差作为AE调用多路复用函数时的超时时间,以及时的处理要过期的时间事件。
eventLoop中的events和fired是两块内存buffer,events保存所有要监视的文件描述符,它的容量可以包含最大的文件描述符数量的文件事件信息,而fired保存所有的已发生的文件的信息。
aeMain
aeMain是AE的启动函数,也是AE的事件循环,主程序的循环也起始于这个函数:
void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0;
while (!eventLoop->stop) {
if (eventLoop->beforesleep != NULL)
eventLoop->beforesleep(eventLoop);
aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}
}