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 ...
随机推荐
- invalid derived query的解决办法
标签: eclipse / invalid / derived / 解决办法 / 校验功能 479 在Eclipse的运行过程中,突然有一个接口跳出如下错误: invalid derived quer ...
- JS中函数之外不能写return
JS中return有时会遇到这种情况,具体表现为:google浏览器等浏览器可以继续执行,IE浏览器不能执行return,并且google浏览器:执行时会显示SyntaxError: Illegal ...
- JAVA基础补漏--多态
Fu obj = new ZI(); 访问成员变量规则 编译看左,运行看左. obj.num; 1.直接通过对象名访问成员变量:看等号左右是谁,优先用谁,没有则往上找. obj.getnum(); 2 ...
- hadoop 2.7.3 源码编译教程
1.工具准备,最靠谱的是hadoop说明文档里要求具备的那些工具. 到hadoop官网,点击source下载hadoop-2.7.3-src.tar.gz. 解压之 tar -zxvf hadoop- ...
- CocoaPods学习系列5——错误集锦
这篇文章记录使用CocoaPods过程中遇到的一些错误. 1.error:include of non-modular header inside framework module 在自定义类库中,引 ...
- Flume-NG源码阅读之AvroSink
org.apache.flume.sink.AvroSink是用来通过网络来传输数据的,可以将event发送到RPC服务器(比如AvroSource),使用AvroSink和AvroSource可以组 ...
- js插件封装
插件封装原则 1.暴露出来的实例必须只能是一个 2.IIFE包裹 !执行包裹 函数作用域保护 3.实例化方法不要写在函数内 throw这个方法是报错
- pandas 选取数据 修改数据 loc iloc []
pandas选取数据可以通过 loc iloc [] 来选取 使用loc选取某几列: user_fans_df = sample_data.loc[:,['uid','fans_count']] 使 ...
- Dib to Bitmap doesn't work in WPF
一.Dib to Bitmap doesn't work in WPF 代码如下: protected byte[] BitmapFromDIB(IntPtr pDIB, IntPtr pPix) { ...
- 【zzulioj-2115】乘积最大(区间dp)
题目描述 今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年.在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得 ...