redis中的事件处理

redis中的事件分为文件事件和时间事件。redis中用aeEventLoop 来记录事件的状态
typedef struct aeEventLoop {

    // 文件事件
    aeFileEvent *events; /* Registered events */

    // 时间事件
    aeTimeEvent *timeEventHead;

} aeEventLoop;
我们所说的文件事件和时间事件也是作为结构的成员变量保存在aeEventLoop中
其中保存文件事件的结构体变量如下:
typedef struct aeFileEvent {

    // 监听事件类型掩码,
    int mask; /* one of AE_(READABLE|WRITABLE) */

    // 读事件的回调函数
    aeFileProc *rfileProc;

    // 写事件的回调函数
    aeFileProc *wfileProc;

    // 读事件和写事件的形参
    void *clientData;

} aeFileEvent;
表示时间事件的结构体如下所示:
typedef struct aeTimeEvent {
    long long id; /* time event identifier. */

    // 事件的到达时间
    long when_sec; /* seconds */
    long when_ms; /* milliseconds */

    // 事件处理函数
    aeTimeProc *timeProc;

    aeEventFinalizerProc *finalizerProc;

    // 时间处理函数的形参
    void *clientData;

    //下一个时间事件的指针
    struct aeTimeEvent *next;

} aeTimeEvent;

redis时间处理的策略可以分为下面四种
#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else
    #ifdef HAVE_EPOLL
    #include "ae_epoll.c"
    #else
        #ifdef HAVE_KQUEUE
        #include "ae_kqueue.c"
        #else
        #include "ae_select.c"
        #endif
    #endif
#endif
这四种根据编译时选择哪个宏来决定,选择不同的策略性能可能会有区别,理论性能从大到小分别是HAVE_EVPORT > HAVE_EPOLL > HAVE_KQUEUE > select(默认)

redis的事件处理的函数如下:
void aeMain(aeEventLoop *eventLoop) {

    eventLoop->stop = 0;
	// 可见处理事件的是一个死循环
    while (!eventLoop->stop) {

        // 在时间处理之前可以调用sleep函数
        if (eventLoop->beforesleep != NULL)
            eventLoop->beforesleep(eventLoop);

        // 开始处理时间和文件事件
        aeProcessEvents(eventLoop, AE_ALL_EVENTS);
    }
}

int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{
    int processed = 0, numevents;

    /* Nothing to do? return ASAP */
	// 如果目前没有时间和文件事件,则直接返回0
    if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0;

    /* Note that we want call select() even if there are no
     * file events to process as long as we want to process time
     * events, in order to sleep until the next time event is ready
     * to fire. */
    if (eventLoop->maxfd != -1 ||
        ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) {
        int j;
        aeTimeEvent *shortest = NULL;
        struct timeval tv, *tvp;

        // 获取最近的时间事件
        if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT))
            shortest = aeSearchNearestTimer(eventLoop);
        if (shortest) {

            long now_sec, now_ms;

            /* Calculate the time missing for the nearest
             * timer to fire. */

            // 得到当前系统时间
            aeGetTime(&now_sec, &now_ms);
            tvp = &tv;
            tvp->tv_sec = shortest->when_sec - now_sec;
			// 比较最近时间事件的时间和现在系统时间的差值
            if (shortest->when_ms < now_ms) {
                tvp->tv_usec = ((shortest->when_ms+1000) - now_ms)*1000;
                tvp->tv_sec --;
            } else {
                tvp->tv_usec = (shortest->when_ms - now_ms)*1000;
            }

            // 差值小于零,说明这个时间事件已经到期,将这个时间事件的时间清零
            if (tvp->tv_sec < 0) tvp->tv_sec = 0;
            if (tvp->tv_usec < 0) tvp->tv_usec = 0;
        } else {
        
            /* If we have to check for events but need to return
             * ASAP because of AE_DONT_WAIT we need to set the timeout
             * to zero */
            if (flags & AE_DONT_WAIT) {
                // 设置文件事件不阻塞
                tv.tv_sec = tv.tv_usec = 0;
                tvp = &tv;
            } else {
                /* Otherwise we can block */
                // 文件事件可以阻塞直到有事件到达为止
                tvp = NULL; /* wait forever */
            }
        }

        // 开始处理文件事件
        numevents = aeApiPoll(eventLoop, tvp);
        for (j = 0; j < numevents; j++) {
            // 从fired数组中得到已经就绪的文件事件
            aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];

            int mask = eventLoop->fired[j].mask;
            int fd = eventLoop->fired[j].fd;
            int rfired = 0;

           /* note the fe->mask & mask & ... code: maybe an already processed
             * event removed an element that fired and we still didn't
             * processed, so we check if the event is still valid. */
            // 读事件处理
            if (fe->mask & mask & AE_READABLE) {
                 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++;
        }
    }

    /* Check time events */
    // 执行时间事件
    if (flags & AE_TIME_EVENTS)
        processed += processTimeEvents(eventLoop);

    return processed; /* return the number of processed file/time events */
}
从这里看文件事件比时间事件优先处理

static int processTimeEvents(aeEventLoop *eventLoop) {
    int processed = 0;
    aeTimeEvent *te;
    long long maxId;
    time_t now = time(NULL);
    if (now < eventLoop->lastTime) {
        te = eventLoop->timeEventHead;
        while(te) {
            te->when_sec = 0;
            te = te->next;
        }
    }
    // 更新最后一次处理时间事件的时间
    eventLoop->lastTime = now;

    // 遍历链表,找到需要处理的时间事件
    te = eventLoop->timeEventHead;
    maxId = eventLoop->timeEventNextId-1;
    while(te) {
        long now_sec, now_ms;
        long long id;

        //无效时间不用处理
        if (te->id > maxId) {
            te = te->next;
            continue;
        }
        
        // 获取当前系统时间
        aeGetTime(&now_sec, &now_ms);

        //事件到期时间小于当前系统时间
        if (now_sec > te->when_sec ||
            (now_sec == te->when_sec && now_ms >= te->when_ms))
        {
            int retval;

            id = te->id;
            // 执行时间事件的回调函数
            retval = te->timeProc(eventLoop, id, te->clientData);
            processed++;
         

            // 根据时间事件的返回值决定是定时事件还是周期事件
            if (retval != AE_NOMORE) {
                // 周期事件,更新这个时间事件下一次到期时间
                aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms);
            } else {
                // 普通定时事件处理完成后则删除
                aeDeleteTimeEvent(eventLoop, id);
            }
            te = eventLoop->timeEventHead;
        } else {
            te = te->next;
        }
    }
    return processed;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值