AE事件庫
AE事件庫是Redis作者自己寫的一個(gè)輕型的異步網(wǎng)絡(luò)庫,不同于Libevent的臃腫,ae保持著它的輕量高效的特點(diǎn)。
Reactor模式
說到異步就不能不說說Reactor模式,這是廣泛應(yīng)用的一種服務(wù)端開發(fā)模式,它本著don't call us,we will call you的思想,將同步阻塞的代碼變成了基于事件回調(diào)的模式。
準(zhǔn)確的說就是有一個(gè)不斷循環(huán)的線程,這個(gè)線程會(huì)不斷的輪詢發(fā)生的事件,然后挨個(gè)處理所發(fā)生的事件,調(diào)用事件事先注冊(cè)好的回調(diào)函數(shù),這個(gè)線程就被稱作Reactor。
AE底層實(shí)現(xiàn)
ae的實(shí)現(xiàn)根據(jù)操作系統(tǒng)的不同會(huì)采用最高效的I/O多路復(fù)用機(jī)制:
/* 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優(yōu)先使用epoll>kqueue>select的順序去選擇I/O多路復(fù)用的底層實(shí)現(xiàn)。
AE主要包括的幾個(gè)部分
EventLoop
事件循環(huán),這不僅是AE,也是Redis最重要的一個(gè)部分。它是一個(gè)結(jié)構(gòu)體,里面保存著事件循環(huán)總體的信息,比如:
時(shí)間事件的鏈表頭,最大的文件描述符,sleep前要執(zhí)行的任務(wù)函數(shù)等。
事件
AE中事件分為文件事件和時(shí)間事件兩種,對(duì)于文件事件來說就是調(diào)用多路復(fù)用函數(shù)去收集到的發(fā)生的事件,對(duì)于每個(gè)文件事件,又分為讀事件和寫事件兩種,分別調(diào)用對(duì)應(yīng)的回調(diào)函數(shù)去處理他們。
而時(shí)間事件在eventLoop中以一個(gè)鏈表的形式存在,在調(diào)用多路復(fù)用函數(shù)的時(shí)候,AE會(huì)去查詢最近的一個(gè)時(shí)間事件,并用它的發(fā)生時(shí)間-當(dāng)前時(shí)間的差作為AE調(diào)用多路復(fù)用函數(shù)時(shí)的超時(shí)時(shí)間,以及時(shí)的處理要過期的時(shí)間事件。
eventLoop中的events和fired是兩塊內(nèi)存buffer,events保存所有要監(jiān)視的文件描述符,它的容量可以包含最大的文件描述符數(shù)量的文件事件信息,而fired保存所有的已發(fā)生的文件的信息。
aeMain
aeMain是AE的啟動(dòng)函數(shù),也是AE的事件循環(huán),主程序的循環(huán)也起始于這個(gè)函數(shù):
void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0;
while (!eventLoop->stop) {
if (eventLoop->beforesleep != NULL)
eventLoop->beforesleep(eventLoop);
aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}
}