1. redis事件的定义

/* State of an event based program */
typedef struct aeEventLoop {int maxfd;   /* highest file descriptor currently registered */int setsize; /* max number of file descriptors tracked */long long timeEventNextId; /*下一个定时器的id*/time_t lastTime;     /* Used to detect system clock skew */aeFileEvent *events; /* Registered events注册的文件事件  */aeFiredEvent *fired; /* Fired events 已注销的文件事件 */aeTimeEvent *timeEventHead;  /*定时器事件链表的首部*/

    int stop; 

    void *apidata; /* This is used for polling API specific data */
    aeBeforeSleepProc *beforesleep;     } aeEventLoop;

1.1 事件定义

/* File event structure */
typedef struct aeFileEvent {
int mask; /* one of AE_(READABLE|WRITABLE) */
aeFileProc *rfileProc;
aeFileProc *wfileProc;
void *clientData;
} aeFileEvent;

/* Time event structure */
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 */
typedef struct aeFiredEvent {
int fd;
int mask;
} aeFiredEvent;

 

2.封装事件处理的实现

/* Include the best multiplexing layer supported by this system.* The following should be ordered by performances, descending. */
#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

3.事件处理的主函数

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

3.1事件处理过程

/* Process every pending time event, then every pending file event* (that may be registered by time event callbacks just processed).* Without special flags the function sleeps until some file event* fires, or when the next time event occurs (if any).** If flags is 0, the function does nothing and returns.* if flags has AE_ALL_EVENTS set, all the kind of events are processed.* if flags has AE_FILE_EVENTS set, file events are processed.* if flags has AE_TIME_EVENTS set, time events are processed.* if flags has AE_DONT_WAIT set the function returns ASAP until all* the events that's possible to process without to wait are processed.** The function returns the number of events processed. */
int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{int processed = 0, numevents;/* Nothing to do? return ASAP */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++) {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 */
}

/* Process time events */
static int processTimeEvents(aeEventLoop *eventLoop) {int processed = 0;aeTimeEvent *te;long long maxId;time_t now = time(NULL);/* If the system clock is moved to the future, and then set back to the* right value, time events may be delayed in a random way. Often this* means that scheduled operations will not be performed soon enough.** Here we try to detect system clock skews, and force all the time* events to be processed ASAP when this happens: the idea is that* processing events earlier is less dangerous than delaying them* indefinitely, and practice suggests it is. */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++;/* After an event is processed our time event list may* no longer be the same, so we restart from head.* Still we make sure to don't process events registered* by event handlers itself in order to don't loop forever.* To do so we saved the max ID we want to handle.** FUTURE OPTIMIZATIONS:* Note that this is NOT great algorithmically. Redis uses* a single time event so it's not a problem but the right* way to do this is to add the new elements on head, and* to flag deleted elements in a special way for later* deletion (putting references to the nodes to delete into* another linked list). */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;
}

转载于:https://www.cnblogs.com/davidwang456/p/3506340.html

深入redis内部--事件处理机制相关推荐

  1. 让人秒懂的Redis的事件处理机制

    redis是单进程,单线程模型,与nginx的多进程不同,与golang的多协程也不同,"工作的工人"那么少,可那么为什么redis能这么快呢? epoll多路复用 这里重点要说的 ...

  2. Redis 处理客户端连接的一些内部实现机制

    本文主要介绍了 Redis 处理客户端连接的一些内部实现机制,包括连接处理.超时.缓冲区等一系列内容. 注:本文所述内容基于 Redis2.6 及以上版本. 连接的建立 Redis 通过监听一个 TC ...

  3. 分析内部运行机制,教你解决Redis性能问题

    摘要:聚焦Redis的性能分析,思考Redis 可以通过哪些机制来提高性能,当性能瓶颈发生的时候,我们又能做出哪些优化策略,最终确保业务系统的稳定运行. 本文分享自华为云社区<分析内部运行机制, ...

  4. Redis 数据同步机制分析

    Redis的主从同步机制可以确保redis的master和slave之间的数据同步.按照同步内容的多少可以分为全同步和部分同步:按照同步的时机可以分为slave刚启动时的初始化同步和正常运行过程中的数 ...

  5. java事件处理模型_从零开始理解JAVA事件处理机制(3)

    我们连续写了两小节的教师-学生的例子,必然觉得无聊死了,这样的例子我们就是玩上100遍,还是不知道该怎么写真实的代码.那从本节开始,我们开始往真实代码上面去靠拢. 事件最容易理解的例子是鼠标事件:我们 ...

  6. QT开发(十二)——QT事件处理机制

    一.QT事件简介 QT程序是事件驱动的, 程序的每个动作都是由内部某个事件所触发.QT事件的发生和处理成为程序运行的主线,存在于程序整个生命周期. 常见的QT事件类型如下: 键盘事件: 按键按下和松开 ...

  7. redis内部数据结构深入浅出

    最大感受,无论从设计还是源码,Redis都尽量做到简单,其中运用到的原理也通俗易懂.特别是源码,简洁易读,真正做到clean and clear, 这篇文章以unstable分支的源码为基准,先从大体 ...

  8. redis lua 设置过期_详解 Redis 内存管理机制和实现

    Redis是一个基于内存的键值数据库,其内存管理是非常重要的.本文内存管理的内容包括:过期键的懒性删除和过期删除以及内存溢出控制策略. 最大内存限制 Redis使用 maxmemory 参数限制最大可 ...

  9. tomcat事件处理机制

    最近在阅读"how tomcat works"这本书,结合tomcat7的源码进行学习.对于学习的收获,将通过"tomcat学习系列"记录下来,和大家一起分享和 ...

最新文章

  1. 打造 AI Beings,和微信合作…第七代微软小冰的成长之路
  2. 申请补办 CET(纸笔考试)成绩证明的方法
  3. php类常量的特点,php类常量是什么?类常量用法详解
  4. 多次点击android版本出现棒棒糖,android – 为前棒棒糖设备创建循环显示
  5. python可变类型与不可变类型作为函数参数区别_不要用可变类型对象做函数默认参数...
  6. ISNULL与CASE函数
  7. MySql常用语句总结更新
  8. JLINK 驱动安装和配置ADS使用,ADX调试
  9. linux系统双显卡切换显卡驱动,自动化系统Linux显卡驱动及BIOS设置笔记(NVIDIA/ATI)...
  10. python爬取全国真实地址_python爬虫学习之爬取全国各省市县级城市邮政编码
  11. 集成学习【三】:Bagging结合神经网络及代码实现
  12. jupyter运行环境配置
  13. GHOST的口诀:备份122、还原123
  14. 什么是linux文件句柄,Linux中的“陈旧文件句柄”是什么意思?
  15. 关于开源软件名字的由来
  16. L1-7 谷歌的招聘
  17. 英文作业写作怎么做到锦上添花?
  18. Glide 问题 You cannot start a load for a destroyed activity
  19. limma | 配对样本的差异分析怎么搞!?(一)
  20. Nginx下配置codeigniter框架方法

热门文章

  1. python数据挖掘例题_数据挖掘与python实践试题及答案
  2. php mac 常用代码,在Mac上使用PHP exec shell(代码签名)重新分配IPA
  3. php pdo bind,PHPPDOStatement对象bindpram()、bindvalue()和bindcolumn之间的区别_php技巧
  4. 8086的内存分段机制
  5. linux限制pptp连接数_性能调优,让你的服务器更强大!增加TCP连接最大限制
  6. linux开机自动打开全屏,如何修改Linux开机启动logo并使其全屏显示?
  7. activity中fragment 返回键不退出_优雅地处理加载中(loading),重试(retry)和无数据(empty)等...
  8. java自己写一个上下文_5.自己动手写Java Web框架-上下文
  9. python及pip中常用命令,经常总结
  10. 数据挖掘流程(六):写报告