Redis源码阅读-事件模型ae
源码文件
- src/ae.c
入口函数
src/ae.c下的void aeMain(aeEventLoop *eventLoop)函数; 推荐从这个函数开始阅读1
2
3
4
5
6
7
8
9
10
11
12
13
14/*
* 事件处理器的主循环
*/
void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0;
while (!eventLoop->stop) {
// 如果有需要在事件处理前执行的函数,那么运行它
if (eventLoop->beforesleep != NULL)
eventLoop->beforesleep(eventLoop);
// 开始处理事件
aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}
}- 我们着重看下
aeMain里面aeProcessEvents(eventLoop, AE_ALL_EVENTS)做了什么; 这里我们留意一下里面的aeApiPoll函数, 该函数用于获取可执行的事件, 获取之后在下面的for循环中处理事件, 执行事件处理器fe->rfileProc(eventLoop,fd,fe->clientData,mask) aeApiPoll函数是ae模块提供的一个接口, 在ae_epoll.cae_kqueue.cae_select.cae_evport.c都做了相应的具体实现, 也是所谓IO多路复用各平台的具体实现, 目的为了兼容不同平台- 备注: 也许你会好奇为啥
IO多路复用没有iocp的实现难道windows就没人权吗, 其实redis的官方版本是不支持windows的, windows版本在https://github.com/microsoftarchive/redis由微软团队自己维护, 里面就有ae_wsiocp.c即iocp版的实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26int aeProcessEvents(aeEventLoop *eventLoop, int flags) {
... ...
// 处理文件事件
numevents = aeApiPoll(eventLoop, tvp);
for (j = 0; j < numevents; j++) {
// 从已就绪数组中获取事件
aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];
int mask = eventLoop->fired[j].mask;
int fd = eventLoop->fired[j].fd;
int rfired = 0;
// 读事件
if (fe->mask & mask & AE_READABLE) {
// rfired 确保读/写事件只能执行其中一个
rfired = 1;
fe->rfileProc(eventLoop,fd,fe->clientData,mask);
}
// 写事件
if (fe->mask & mask & AE_WRITABLE) {
if (!rfired || fe->wfileProc != fe->rfileProc)
fe->wfileProc(eventLoop,fd,fe->clientData,mask);
}
processed++;
}
... ...
} - 通常说的redis的
reactor模型(反应堆)其实说的就是aeMain的大循环中aeProcessEvents做的那些事情:监听网络连接的FD的文件事件---> 获取事件---> 执行事件回调 - 剩下具体细节不多赘述, 顺着思路看源码即可