核心内容摘要
Bing蜘蛛IP地址段2025最新版:一键导入Nginx/Apache屏蔽恶意爬虫
文章目录事件循环线程事件循环相关源码文件事件主循环机制睡眠钩子Hooks机制睡眠钩子的实现Epoll 实战键盘输入监听事件循环线程众所周知Redis 服务器启动时会开启六个线程Thread-1 [redis-server]主线程Thread-2 [bio_close_file]后台 I/O 线程 - 文件关闭Thread-3 [bio_aof]后台 I/O 线程 - AOF 刷盘Thread-4 [bio_lazy_free]后台 I/O 线程 - 惰性删除Thread-5 [jemalloc_bg_thd]内存整理线程Thread-6 [jemalloc_bg_thd]内存整理线程而事件循环则位于Thread-1 [redis-server]主线程中。
事件循环相关源码文件源码文件说明ae.c事件驱动循环核心ae_epoll.cLinux 系统实现epollae_evport.cSolaris 专用ae_kqueue.cmacOS 专用ae_select.c老旧 Linux 或兼容模式使用ebuckets.c事件桶管理eventnotifier.c事件通讯器事件主循环机制Redis 的事件主循环位于ae.c中核心代码如下voidaeMain(aeEventLoop*eventLoop){eventLoop-stop0;while(!eventLoop-stop){aeProcessEvents(eventLoop,AE_ALL_EVENTS|AE_CALL_BEFORE_SLEEP|AE_CALL_AFTER_SLEEP);}}但死循环非常消耗 CPURedis 是如何让线程进入睡眠等待的呢真正的“睡眠”发生在aeApiPoll中其核心是调用系统epoll_waitstaticintaeApiPoll(aeEventLoop*eventLoop,structtimeval*tvp){aeApiState*stateeventLoop-apidata;intretval,numevents0;retvalepoll_wait(state-epfd,state-events,eventLoop-setsize,tvp?(tvp-tv_sec*1000(tvp-tv_usec
/
:-
;if(retval
{intj;numeventsretval;for(j0;jnumevents;j){intmask0;structepoll_event*estate-eventsj;if(e-eventsEPOLLIN)mask|AE_READABLE;if(e-eventsEPOLLOUT)mask|AE_WRITABLE;if(e-eventsEPOLLERR)mask|AE_WRITABLE|AE_READABLE;if(e-eventsEPOLLHUP)mask|AE_WRITABLE|AE_READABLE;eventLoop-fired[j].fde-data.fd;eventLoop-fired[j].maskmask;}}elseif(retval-1errno!EINTR){panic(aeApiPoll: epoll_wait, %s,strerror(errno));}returnnumevents;}epoll_wait就是实现“睡眠”的系统调用。
当没有事件时线程在此阻塞不消耗 CPU。
睡眠钩子Hooks机制为了在睡眠前后执行必要逻辑Redis 提供了钩子函数。
在initServer函数中注册aeSetBeforeSleepProc(server.el, beforeSleep); aeSetAfterSleepProc(server.el, afterSleep);在aeProcessEvents中调用if (eventLoop-beforesleep ! NULL (flags AE_CALL_BEFORE_SLEEP)) eventLoop-beforesleep(eventLoop); if (eventLoop-aftersleep ! NULL flags AE_CALL_AFTER_SLEEP) eventLoop-aftersleep(eventLoop);作用beforeSleep处理客户端写回、检查阻塞超时、计算下一次epoll_wait的超时时间等。
afterSleep清理或重置休眠期间的状态。
这些钩子避免了无限循环中 CPU 空转是 Redis 高效的核心之一。
睡眠钩子的实现beforeSleep钩子和afterSleep钩子的实现都在server.c中分别是void beforeSleep(struct aeEventLoop *eventLoop)和void afterSleep(struct aeEventLoop *eventLoop)。
实现上beforeSleep远比afterSleep复杂。
Epoll 实战键盘输入监听我们可以编写代码练习epoll的使用模拟 Redis 的事件监听机制。
#includestdio.h#includestdlib.h#includesys/epoll.h#includeunistd.h// 简单的错误处理宏#definepanic(fmt,...)\do{fprintf(stderr,FATAL ERROR: fmt (%s:%d)\n,##__VA_ARGS__,__FILE__,__LINE__);\exit(