Redis事件管理

Posted 扫地猿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis事件管理相关的知识,希望对你有一定的参考价值。

Redis的定时器是自己实现的,不是很复杂。说说具体的实现吧。

定时器的存储维护采用的是普通的单向链表结构,具体节点定义为:

 1 /*时间定时器结构体*/
 2 typedef struct aeTimeEvent 
 3 {
 4     long long id; /*定时器的编号*/
 5     long when_sec; /* seconds */
 6     long when_ms; /* milliseconds */
 7     aeTimeProc *timeProc;/*时间到达处理函数*/
 8     aeEventFinalizerProc *finalizerProc;/*删除清理函数*/
 9     void *clientData;/*带外数据*/
10     struct aeTimeEvent *next;/*定时器的存储采用的是链表结构*/
11 } aeTimeEvent;

定时器记录的根节点的位置是在事件管理器中,剩下的就是普通的操作函数了

 1 /*添加定时器事件,参数为时间控制器,定时时间,处理函数,函数参数,清理函数*/
 2 long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
 3         aeTimeProc *proc, void *clientData,
 4         aeEventFinalizerProc *finalizerProc)
 5 {
 6     /*生成ID*/
 7     long long id = eventLoop->timeEventNextId++;
 8     aeTimeEvent *te;
 9 
10     te = zmalloc(sizeof(*te));
11     if (te == NULL) return AE_ERR;
12     te->id = id;
13     /*调整时间*/
14     aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms);
15     te->timeProc = proc;
16     te->finalizerProc = finalizerProc;
17     te->clientData = clientData;
18     /*加入时间链表中,所有的时间节点都是在头部插入的,没顺序*/
19     te->next = eventLoop->timeEventHead;
20     eventLoop->timeEventHead = te;
21     return id;
22 }
 1 /*删除时间节点,提供时间点的ID就好,如果没找到就返回错误*/
 2 int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id)
 3 {
 4     aeTimeEvent *te, *prev = NULL;
 5 
 6     te = eventLoop->timeEventHead;
 7     /*循环查找节点,调用清理函数并释放内存*/
 8     while(te) 
 9     {
10         if (te->id == id) 
11         {
12             if (prev == NULL)
13                 eventLoop->timeEventHead = te->next;
14             else
15                 prev->next = te->next;
16             if (te->finalizerProc)
17                 te->finalizerProc(eventLoop, te->clientData);
18             zfree(te);
19             return AE_OK;
20         }
21         prev = te;
22         te = te->next;
23     }
24     return AE_ERR; /* NO event with the specified ID found */
25 }
 1 /*查找激活时间最短的节点*/
 2 static aeTimeEvent *aeSearchNearestTimer(aeEventLoop *eventLoop)
 3 {
 4     aeTimeEvent *te = eventLoop->timeEventHead;
 5     aeTimeEvent *nearest = NULL;
 6 
 7     while(te) 
 8     {
 9         if (!nearest || te->when_sec < nearest->when_sec || (te->when_sec == nearest->when_sec && te->when_ms < nearest->when_ms))
10             nearest = te;
11         te = te->next;
12     }
13     return nearest;
14 }
 1 /* Process time events 处理时间事件,先执行定时器事件,如果有时间设置过端的情况,会导致整个卡死*/
 2 static int processTimeEvents(aeEventLoop *eventLoop) 
 3 {
 4     int processed = 0;
 5     aeTimeEvent *te;
 6     long long maxId;
 7     time_t now = time(NULL);
 8 
 9     if (now < eventLoop->lastTime) /*为啥会出现当前时间小于上次激活时间的问题,重新设置了系统时间,当前时间小于了最后的插入时间*/
10     {
11         te = eventLoop->timeEventHead;
12         while(te) 
13         {
14             te->when_sec = 0;
15             te = te->next;
16         }
17     }
18     eventLoop->lastTime = now;/*更新最后操作时间*/
19 
20     te = eventLoop->timeEventHead;
21     maxId = eventLoop->timeEventNextId-1;
22     /*时间处理,从链表中逐个检查,找到到达时间的定时器后调用处理函数,然后重新从头遍历,当某个定时器的*/
23     while(te) 
24     {
25         long now_sec, now_ms;
26         long long id;
27 
28         if (te->id > maxId) 
29         {
30             te = te->next;
31             continue;
32         }
33         aeGetTime(&now_sec, &now_ms);
34         if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms))
35         {/*当该节点时间到达时,调用时间处理函数,根据函数的返回来决定是否需要删除定时节点*/
36             int retval;
37 
38             id = te->id;
39             retval = te->timeProc(eventLoop, id, te->clientData);
40             processed++;
41 
42             /*根据函数的返回值来确定是否仍需注册,返回值为下次的激活时间*/
43             if (retval != AE_NOMORE) 
44             {
45                 /*返回值不为-1时需要重新注册函数,返回值为下次激活的时间*/
46                 aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms);
47             } 
48             else 
49             {
50                 /*删除定时器*/
51                 aeDeleteTimeEvent(eventLoop, id);
52             }
53             /*定时器函数处理完毕之后为了防止漏掉节点,重新从头结点遍历,这个地方要注意,如果定时时间太短,这个地方会造成死循环,不停的处理定时器事件*/
54             te = eventLoop->timeEventHead;
55         } 
56         else 
57         {
58             te = te->next;
59         }
60     }
61     return processed;
62 }

 

以上是关于Redis事件管理的主要内容,如果未能解决你的问题,请参考以下文章

Redis事件管理

Redis事件管理

在每个用户的Rails中使用片段缓存

Redis 内存管理与事件处理

如何使用警报管理器将数据从片段传递到广播接收器

Android 事件分发事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )(代码片段