Redis事件库源码分析
由于老大在新项目中使用redis的事件库代替了libevent,我也趁着机会读了一遍redis的事件库代码,第一次读到“优美,让人愉快”的代码,加之用xmind制作的类图非常帅,所以留文纪念。
Redis的事件库主要集中在ae.h和ae.c中,此外还有ae_epoll.c等底层实现文件,根据系统可选择事件库的实现方式,典型的讲上层实现与底层实现分离的结构。
ae.h是事件库函数的定义与使用的结构体,关于结构体的相互联系可参见类图。

除了事件库,Redis还封装了malloc等内存管理函数,为标准函数增加了一个记录占用内存量的部分,如果想独立使用redis的事件库,只要把ae.c中的zmalloc全部替换成标准malloc即可。
下面开始介绍ae.c,一段典型的ae事件库如下图所示:
int main()
{
aeEventLoop el;
el = aeCreateEventLoop();
aeCreateFileEvent(el, fd, mask, proc, clientData);
aeCreateTimeEvent(el, milliseconds, proc, clientData, finalizerProc);
aeMain(el);
}
aeCreateEventLoop用于对ae事件库进行初始化,然后通过aeCreateFileEvent和aeCreateTImeEvent可以添加需要监控的fd读写事件或者定时事件,通过类图,可以看到对于fd读写时间有两个钩子,一个是读事件的钩子,一个是写时间的钩子;对于定时事件也有两个钩子,一个是定时时间到达时的钩子,一个是delete定时事件时执行的钩子。
创建完我们需要的事件后,调用aeMain进入事件驱动。aeMain中,判断几个执行变量即开始死循环调用aeProcessEvents处理事件。
aeProcessEvents首先需要从时间事件中寻找最近要执行的定时事件时间,此时间与当前时间的间隔即是调用aeApiPoll的超时时间,避免因epoll超时,影响定时事件执行。aeApiPoll会将需要处理的fd事件,放入fired队列,因此调用aeApiPoll之后,是通过遍历fired队列来执行fd事件的。fd事件处理结束,调用processTimeEvents处理定时事件,processTimeEvents每执行一个定时事件都要重新遍历定时事件队列,因为每个定时事件的执行,都会导致当前时间改变,从而有新的事件需要执行,但是processTimeEvents不会处理新加入的时间事件,以免该循环永不退出(但是目前还是有可能因为定时事件执行时间过长而导致循环永不退出)。到此整个ae事件驱动的核心就结束了。
需要注意的是,定时事件的钩子函数需要返回定时事件的时间间隔,或者返回AE_NOMORE表示删除该定时事件,实际上这也允许了我们动态调整定时事件的时间间隔。
Ae时间驱动,可以优化的地方很多,在代码注释中,开发人员解释道,因为redis对事件驱动的使用并不复杂,因此没有进行更多的优化,例如ae的定时事件队列实现上就是一个队列,因此寻找最近要执行的定时事件需要O(n)的复杂度,因为这个问题,执行定时事件时,也需要不断重复遍历定时队列,查找要执行的事件,我想最普遍的想法就是将这个队列实现为堆,或者二叉树,但是redis里建议实现为跳表,跳表的算法我看过一次,没发现特殊的性能优势,有时间还要研究研究。
Redis事件库源码分析的更多相关文章
- Redis网络库源码分析(1)之介绍篇
一.前言 Redis网络库是一个单线程EPOLL模型的网络库,和Memcached使用的libevent相比,它没有那么庞大,代码一共2000多行,因此比较容易分析.其实网上已经有非常多有关这个网络库 ...
- Redis网络库源码分析(3)之ae.c
一.aeCreateEventLoop & aeCreateFileEvent 上一篇文章中,我们已经将服务器启动,只是其中有些细节我们跳过了,比如aeCreateEventLoop函数到底做 ...
- Redis网络库源码分析(2)之启动服务器
一.从main开始 main函数定义在server.c中,它的内容如下: //server.c int main() { signal(SIGPIPE, SIG_IGN); //忽略SIGPIPE信号 ...
- ApplicationEvent事件机制源码分析
<spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情> <服务网关zu ...
- Zepto事件模块源码分析
Zepto事件模块源码分析 一.保存事件数据的handlers 我们知道js原生api中要移除事件,需要传入绑定时的回调函数.而Zepto则可以不传入回调函数,直接移除对应类型的所有事件.原因就在于Z ...
- Redis网络模型的源码分析
Redis的网络模型是基于I/O多路复用程序来实现的.源码中包含四种多路复用函数库epoll.select.evport.kqueue.在程序编译时会根据系统自动选择这四种库其中之一.下面以epoll ...
- Redis 内存管理 源码分析
要想了解redis底层的内存管理是如何进行的,直接看源码绝对是一个很好的选择 下面是我添加了详细注释的源码,需要注意的是,为了便于源码分析,我把redis为了弥补平台差异的那部分代码删了,只需要知道有 ...
- springBoot集成Redis遇到的坑(择库)源码分析为什么择库失败
提示: springboot提供了一套链接redis的api,也就是个jar包,用到的连接类叫做LettuceConnectionConfiguration,所以我们引入pom时是这样的 <de ...
- cJSON库源码分析
本文采用以下协议进行授权: 自由转载-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 ,转载请注明作者及出处. cJSON是一个超轻巧,携带方便,单文件,简单的可以作为A ...
随机推荐
- 华丽的使用sublime写lua~ sublime lua相关必装插件推荐~~
缘起 lua脚本语言虽好,代码写得飞快,可是写错了调试起来却很困难,lua使用者经常容易犯得一个错误是--写错变量名了,if end 嵌套太多没匹配~,多打了一个逗号, --假设定义了一个变量 loc ...
- 用maven创建web工程
1.打开eclipse,选择File->New->Other菜单,弹出下面的对话框,在Wizards中输入maven,会过滤出和maven相关的菜单,选中Maven Project菜单,然 ...
- javascript日期格式处理
一. 服务端返回的日期和时间之间有T Asp.net MVC中 action返回前台的日期类型数据 是带有 T的,如: 2015-07-07T10:15:01. 这样的数据在Chrome浏览器,会自动 ...
- SpiralOrderTraverse,螺旋遍历二叉树,利用两个栈
问题描述:s型遍历二叉树,或者反s型遍历二叉树 算法分析:层序遍历二叉树只需要一个队列,因为每一层都是从左往右遍历,而s型遍历二叉树就要用两个栈了,因为每次方向相反. public static vo ...
- apue.3e源码下载及编译
下载地址:http://www.apuebook.com/code3e.html 编译方法:http://blog.sina.com.cn/s/blog_94977c890102vdms.html
- JNI_Z_01_获取Clazz
1. 为了能够在C/C++中使用Java类,jni.h头文件中专门定义了jclass类型来表示Java中的Class类(ZC: 就是Clazz) 2. 2.1.JNIEXPORT void JNICA ...
- Educational Codeforces Round 23F
http://codeforces.com/contest/817/problem/F 无限长的数组,刚开始每一位是0,三种操作,1,把(l,r)之间不是1的变成1,2,把(l,r)之间不是0的变成0 ...
- 三十八 Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)介绍以及安装
elasticsearch(搜索引擎)介绍 ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口.Elasticse ...
- iOS唯一标示符引导
在2013年3月21日苹果已经通知开发者,从2013年5月1日起,访问UIDID的应用将不再能通过审核,替代的方案是开发者应该使用“在iOS 6中介绍的Vendor或Advertising标 ...
- iptables(四)iptables匹配条件总结之一
经过前文的总结,我们已经能够熟练的管理规则了,但是我们使用过的"匹配条件"少得可怜,之前的示例中,我们只使用过一种匹配条件,就是将"源地址"作为匹配条件. 那么 ...