redis的ae事件模型

事件循环的数据结构aeEventLoop
typedef struct aeEventLoop {
    int maxfd;   /* 当前注册的最大文件描述符 */
    int setsize; /* 允许的最大文件描述符 */
    long long timeEventNextId; 
    time_t lastTime;     /* Used to detect system clock skew */
    aeFileEvent *events; /* 注册的事件数组指针 */
    aeFiredEvent *fired; /* 已完成的事件数组指针 */
    aeTimeEvent *timeEventHead; /* 时间事件链表头指针 */
    int stop;
    void *apidata; /* 用来存io复用模型返回已完成事件的数组指针 */
    aeBeforeSleepProc *beforesleep;
} aeEventLoop;
aeEventLoop的初始化 文件事件 时间事件

redis启动初始化时就会创建一个aeEventLoop的实例

aeEventLoop *aeCreateEventLoop(int setsize)

这个函数工作为:
设置最大文件描述符大小 为客户端数量(默认10000)加上128 (以保证安全)
直接申请events和fired的所需的内存空间,大小都为sizeof(aeFileEvent) setsize 可能会有些许的空间浪费 但问题不大
其他变量初始化
返回一个事件循环的指针

其中aeFileEvent数据结构如下

/* File event structure */
typedef struct aeFileEvent {
    int mask; /* one of AE_(READABLE|WRITABLE) 标准这是一个读事件还是写事件*/
    aeFileProc *rfileProc; /* 读事件时执行的函数 */
    aeFileProc *wfileProc; /* 写事件时执行的函数 */
    void *clientData;
} aeFileEvent;

aeTimeEvent数据结构如下

typedef struct aeTimeEvent {
    long long id; /* 事件id 是不断递增的 */
    long when_sec; /* 执行事件的时间(秒数) */
    long when_ms; /*  执行事件的时间(毫秒数) */
    aeTimeProc *timeProc; /* 执行的函数 */
    aeEventFinalizerProc *finalizerProc; /* 时间事件从链表中删除时执行的函数 非必须 */
    void *clientData;
    struct aeTimeEvent *next; /* 下一个时间事件的指针 */
} aeTimeEvent;
时间事件的注册

在创建aeEventLoop之后会注册第一个时间事件函数(serverCron),做一些异步/定时的操作,其中注册事件的函数为

long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
        aeTimeProc *proc, void *clientData,
        aeEventFinalizerProc *finalizerProc)

这个函数工作为:
创建一个时间事件(aeTimeEvent), 并把这个新创建的时间事件放到链表的头部 (时间事件的存储结构是链表而不是如同文件事件一样是数组)
返回新建事件的id

文件事件的注册

注册第一个时间事件serverCron之后注册 监听端口(tcp socket) 的文件描述符fd和处理连接的函数acceptTcpHandler 为可读的文件事件 注册文件事件的函数为

int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
        aeFileProc *proc, void *clientData)

这个函数工作为:
将文件事件的mask和proc 放到对应的eventLoop->events[fd]内,(索引值就是fd),同时使用epoll_clt注册该fd (也可以是select kqueue,编译时根据操作系统确定)
返回自定义的成功/失败值(AE_OK AE_ERR)

事件循环

时间事件和文件事件的执行函数为 (只要eventLoop->stop为0就会一直循环执行)

int aeProcessEvents(aeEventLoop *eventLoop, int flags)

这个函数主要工作为:
首先获取距当前时间 最近一次将要执行的时间事件的 时间(如果负数 则赋为0)(会遍历整个链表)
然后执行aeApiPoll函数 获取已经可读/写的文件描述符 (存在eventLoop的fired数组中), 以epoll_wait为例, epoll_wait调用的等待时间为上述获取时间。 (若没有时间事件或为0 则不进行阻塞 无论有无事件完成都立即返回)
之后遍历eventLoop->fired数组 (索引值不等于fd, 数组长度由aeApiPoll返回值确定),执行对应的事件的fd在eventLoop->events中注册的读/写函数
最后执行processTimeEvents函数,遍历时间事件链表,先检查被标记为删除的事件并删除(如果设置finalizerProc就执行),再执行扔在链表里且时间已到的事件。根据timePorc的返回值是否等于AE_NOMORE判断执行之后是否对该事件标记为删除。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值