zoukankan      html  css  js  c++  java
  • redis学习笔记(四): ae

    redis是基于事件驱动的,相应的实现都在ae.c当中。

    其实个人对于“事件驱动”的理解不是那么明显,只能说从它的实现上来看稍微有一些感觉:

    先由外部模块注册感兴趣的事件以及callback,在poll返回时判断是否有相应模块感兴趣的事件,如果有的话就调用注册的callback

    /* 代码中的注释是File event structure,个人理解就是外部模块感兴趣的内容以及处理方式。目前用到这个结构的包括:网络事件以及unix套接字上的内部通信 */
    typedef struct aeFileEvent {
    int mask; /* one of AE_(READABLE|WRITABLE) */
    aeFileProc *rfileProc;
    aeFileProc *wfileProc;
    void *clientData;
    } aeFileEvent;
    
    /* 代码中的注释是Time event structure,也就是定时处理的事件,用单链表的形式组织起来。finalizerProc这个成员还不理解有什么作用。目前主进程中应该只有serverCron这一个需要定时处理的事件 */
    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;
    
    /* 代码中的注释是A fired event,其实就是在poll返回时,每一个发生的事件 */
    typedef struct aeFiredEvent {
    int fd;     /* 发生事件的套接字,目前只有inet和unix */
    int mask; /* fd上发生的事件 */
    } aeFiredEvent;
    
    /* 代码中的注释是State of an event based program,个人理解就是对所有事件的管理结构,整个主进程只有一个 */
    typedef struct aeEventLoop {
    int maxfd; /* 当前最大的fd,目前只有select有用 */
    int setsize; /* 这个值就是下面events,fired两个数组的大小 */
    long long timeEventNextId;
    time_t lastTime; /* Used to detect system clock skew */
    aeFileEvent *events; /* 外部注册的感兴趣的事件 */
    aeFiredEvent *fired; /* poll返回的事件 */
    aeTimeEvent *timeEventHead; /* 定时器事件 */
    int stop; /* 如果是1就要退出事件处理流程 */
    void *apidata; /* This is used for polling API specific data */
    aeBeforeSleepProc *beforesleep; /* 进入poll之前需要处理的事情 */
    } aeEventLoop;

    ae.c里面使用如下的方式来决定系统使用的poll机制:

    #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

    虽然每个c文件对应的poll机制不同,但都定义了自己的aeApiState以及实现的都是相同的api: 

    aeApiState,

      每种poll机制内部使用的相关结构体,例如:select用到的fdset, epoll用到的epoll_fd以及events数组

    aeApiCreate,

         poll机制的初始化,每个poll机制都会在这里分配一个新的aeApiState结构,并做一些特定的初始化操作

        例如:对于select来说应该是就是初始化fdset,用于select的相关调用;对于epoll来说,需要创建epoll的fd以及epoll使用的events数组

    aeApiResize,

        调整poll机制中能处理的事件数目,例如:对于select来说,其实只要不超过fdset的最大值(一般系统默认是1024)它就什么都不做,否则返回错误;对于epoll来说,就是重新分配events数组

        这个函数只在config阶段会被调用

    aeApiFree, 

        对于select来说,主要就是释放aeApiState的空间

     对于epoll来说,主要就是关闭epoll的fd, 释放aeApiState以及events的空间

    aeApiAddEvent, 

        对于select来说,就是往某个fd_set里面增加fd

        对于epoll来说,就是在events中增加/修改感兴趣的事件

    aeApiDelEvent, 

        对于select来说,就是从某个fd_set里面删除fd

        对于epoll来说,就是在events中删除/修改感兴趣的事件

    aeApiPoll, 

     主要的poll入口,比如select或者epoll_wait

    aeApiName

     返回poll机制的名字,比如select或者epoll

    ae.c里面实现的主流程其实也很简单

    void aeMain(aeEventLoop *eventLoop) {
        eventLoop->stop = 0;
        while (!eventLoop->stop) {
            if (eventLoop->beforesleep != NULL)
                eventLoop->beforesleep(eventLoop);
            aeProcessEvents(eventLoop, AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP);
        }
    }

    beforesleep主要是一些(进入poll之前的)准备工作或者是处理上一轮poll中未完成任务的最后一步。后面再仔细看这一部分

    aeProcessEvents,第二个参数是AE_ALL_EVENTS,所以在里面会(按顺序)处理file和time两类事件:

    调用aeApiPoll时,需要指定超时时间或者死等。自然地,它会从aeTimeEvent的单链表中找出距离当前最近的定时器事件的超时时间,以该时间做为超时时间调用具体的poll函数(select/epoll_wait)。否则,如果没有找到任何超时事件,则会让poll函数进入死等。

    不过要注意的是,如果aeProcessEvents的第二个参数指定了AE_DONT_WAIT,那么就不能在poll函数上等,会直接把时间设置为0,也就是具体的poll函数会立刻超时。

    aeApiPoll返回之后,处理file事件(如果有的话)。最后,再调用processTimeEvents处理time事件(如果aeProcessEvents的第二个参数指定了AE_TIME_EVENTS标记)

    redis使用ae的大致流程如下:

    {
        ...
        aeCreateEventLoop    /* 创建总的事件管理结构 */
        aeCreateTimeEvent    /* 创建定时器事件的管理结构 */
        aeCreateFileEvent for inet socket    /* 创建网络事件的管理结构 */
        aeCreateFileEvent for unix socket    /* 内部通信事件的管理结构 */
        aeSetBeforeSleepProc    /* 设置beforeSleep处理函数 */
        aeSetAfterSleepProc    /* 设置afterSleep处理函数 */
        ...
        while (!stop)
        {
            beforeSleep                /* 调用beforeSleep处理函数 */
            aeApiPoll                /* 进入poll函数 */
            afterSleep                /* 调用afterSleep处理函数 */
            process file events    /* 处理file events */
            process time events    /* 处理time events */
        }
        ...
    }
  • 相关阅读:
    辅助方法、模型、视图数据
    HTML.Label
    HTML辅助方法
    ViewBag与ViewData
    ASP.NET MVC4 View 指定视图
    ASP.NET MVC4 配置逻辑
    大部分基于MVC的Web框架所使用的一些基本原则
    MVC内置的验证属性
    高德地图多点标记自定义地图
    关于数组的去重
  • 原文地址:https://www.cnblogs.com/flypighhblog/p/7748514.html
Copyright © 2011-2022 走看看