Redis 事件驅動框架(ae.c_ae.h)深度解析

Redis 事件驅動框架(ae.c/ae.h)深度解析

之前咱們用 “超市收銀員” 的例子,簡單看懂了 ae 模塊是 Redis 的 “多任務神器”。現在咱們再往深走一層,不用復雜代碼,只拆它的 “核心運作邏輯”—— 搞懂它怎么做到 “一個收銀員(單線程)高效處理一堆顧客(多請求)”。

一、先明確:ae 模塊到底要解決什么問題?

Redis 剛誕生時,有個關鍵需求:用單線程處理成千上萬的客戶端連接。如果用 “一個連接派一個線程” 的方式,線程多了會互相搶資源(比如內存、CPU),反而變慢。

ae 模塊的作用,就是給單線程裝上 “三頭六臂”—— 讓它能同時 “監聽” 很多連接,哪個連接有請求就處理哪個,還能按時做定時任務(比如清理過期數據)。

二、ae 模塊的 “三大核心零件”

就像一臺機器有幾個關鍵零件,ae 模塊也有三個 “缺一不可” 的核心組件,咱們一個個看:

1. 零件 1:事件循環(aeEventLoop)——“工作總調度臺”

你可以把它想象成收銀員的 “工作臺”,上面放著所有要處理的任務清單。源碼里它是個結構體(簡化后):

struct aeEventLoop {int maxfd;                  // 目前最多有多少個“顧客呼叫鈴”(最大文件描述符)aeFileEvent \*events;        // 所有“呼叫鈴”的清單(文件事件列表)aeTimeEvent \*timeEventHead; // 所有“定時提醒”的清單(時間事件鏈表)int stop;                   // 下班開關(1=停止,0=工作)};

關鍵作用

  • 管理所有 “待處理任務”(不管是客戶端請求,還是定時任務);

  • 控制 “工作流程”:先看有沒有呼叫鈴響,再看有沒有定時提醒到點,循環往復。

2. 零件 2:文件事件(aeFileEvent)——“顧客呼叫鈴”

每個客戶端連接(比如你用命令行連 Redis),在 ae 模塊里都對應一個 “呼叫鈴”—— 這就是文件事件。

簡化結構體:

struct aeFileEvent {int mask;                   // 鈴的類型(讀鈴/寫鈴,比如客戶端發請求是“讀鈴”)aeFileProc \*rfileProc;      // 讀鈴響了要做的事(比如接收客戶端發的命令)aeFileProc \*wfileProc;      // 寫鈴響了要做的事(比如給客戶端返回結果)};

舉個例子

當你在命令行輸入 set name zhangsan 時:

  1. 你的客戶端連接會觸發 “讀鈴”(mask = 讀事件);

  2. ae 模塊會調用 rfileProc 函數,把你輸入的命令接收到 Redis 里。

3. 零件 3:時間事件(aeTimeEvent)——“超市定時提醒”

Redis 里需要 “到點自動做” 的事,比如 “每 10 秒清理一次過期數據”“每天凌晨 3 點做 RDB 備份”,都靠時間事件實現。

簡化結構體:

struct aeTimeEvent {long long id;               // 提醒的唯一編號(避免混亂)long long when\_sec;         // 到點時間(秒)long long when\_ms;          // 到點時間(毫秒,更精確)aeTimeProc \*timeProc;       // 到點要做的事(比如清理過期數據的函數)    struct aeTimeEvent \*next;   // 下一個提醒(鏈表結構,按時間排序)};

關鍵特點

  • 所有時間事件按 “到點時間” 排序,就像你的鬧鐘按時間先后排好;

  • 每次事件循環,只需要檢查 “最早到點” 的提醒(鏈表頭),不用遍歷所有,效率高。

三、ae 模塊的 “工作流程”:單線程怎么高效干活?

咱們用 “超市收銀員” 的場景,再細化一遍 ae 模塊的 “一天工作”—— 對應源碼里的 aeMain 函數(事件循環主函數):

步驟 1:開店前準備(初始化事件循環)

  • 收銀員先擺好 “工作臺”(創建 aeEventLoop 實例);

  • 把超市大門的 “呼叫鈴” 裝上(注冊監聽端口的文件事件,比如 Redis 默認的 6379 端口);

  • 設好 “定時提醒”(比如 “每 10 秒查一次過期商品”)。

步驟 2:開始營業(進入事件循環)

收銀員坐在工作臺前,循環做以下 3 件事:

① 看 “最早的定時提醒還有多久到點”

比如現在有兩個提醒:“10 秒后清理過期商品”“1 小時后備份”,那最早的是 10 秒后。

  • 這個時間決定了 “收銀員最多等多久”—— 如果 10 秒內沒人按呼叫鈴,就等 10 秒后處理定時任務;如果期間有人按鈴,就立刻處理。
② 等 “呼叫鈴響”(監聽文件事件)

收銀員調用 aeApiPoll 函數(底層是 epoll/kqueue 等系統工具),“監聽” 所有呼叫鈴:

  • 如果沒人按鈴,就等第一步算好的時間(比如 10 秒);

  • 如果有人按鈴(比如客戶端發請求),就立刻知道是哪個鈴響了(哪個客戶端)、是讀鈴還是寫鈴。

③ 處理 “響了的鈴” 和 “到點的提醒”
  • 先處理所有 “響了的呼叫鈴”(文件事件):比如客戶 A 要結賬(讀事件),就收他的錢;客戶 B 要拿商品(寫事件),就給他拿。

  • 再處理 “到點的定時提醒”(時間事件):比如 10 秒到了,就去清理過期商品。

步驟 3:關店(停止事件循環)

當 Redis 收到 “shutdown” 命令時,把 aeEventLoopstop 設為 1,事件循環結束,收銀員下班。

四、ae 模塊的 “性能秘密”:為什么單線程能處理萬級連接?

關鍵靠底層的 “IO 多路復用” 技術 —— 對應源碼里的 aeApi* 系列函數(比如 Linux 下的 ae_epoll.c)。

咱們用 “超市” 類比,解釋這個技術:

  • 普通方式(沒有 IO 多路復用):一個顧客一個收銀員,1000 個顧客要 1000 個收銀員,成本高還亂;

  • IO 多路復用方式:一個收銀員守著所有顧客的 “呼叫鈴”,哪個響了處理哪個 —— 相當于 “一個人同時監聽很多連接”,不用開多線程。

Redis 會根據操作系統自動選最優的 “監聽工具”:

  • Linux 用 epoll(最常用,效率最高,支持萬級連接);

  • BSD 用 kqueue(和 epoll 類似,高效);

  • Windows 用 select(效率低,支持連接少,所以 Redis 在 Windows 上很少用)。

五、動手看源碼:怎么快速找到 ae 模塊的核心?

如果你想自己翻源碼,不用全看,找這幾個關鍵地方就行:

  1. ae.c 的 aeCreateEventLoop 函數:看事件循環怎么初始化;

  2. ae.c 的 aeProcessEvents 函數:看一次事件循環的完整流程(對應咱們說的步驟 2);

  3. ae.c 的 aeCreateTimeEvent 函數:看定時任務怎么創建(比如 server.c 里會調用它注冊清理過期數據的任務);

  4. ae_epoll.c(Linux 下):看 epoll 怎么實現 “監聽多個連接”(不用看懂所有代碼,看 aeApiAddEvent 怎么加事件、aeApiPoll 怎么等事件)。

總結

ae 模塊其實就是 Redis 的 “多任務調度中心”:

  • 靠 “事件循環” 統管所有任務;

  • 靠 “文件事件” 處理客戶端連接;

  • 靠 “時間事件” 處理定時任務;

  • 靠 “IO 多路復用” 讓單線程能高效處理萬級連接。

理解了 ae 模塊,你就懂了 Redis 單線程高性能的核心 —— 不是靠 “多線程堆資源”,而是靠 “聰明的任務調度”。

如果還想再深入,比如看 “epoll 具體怎么監聽連接”,或者 “時間事件怎么精確到毫秒”,咱們可以繼續拆!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/98216.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/98216.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/98216.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[能源化工] 面向鋰電池RUL預測的開源項目全景速覽

鋰離子電池是新能源汽車、儲能系統及便攜式電子設備的核心能源部件,其剩余使用壽命(Remaining Useful Life,RUL)的準確預測直接關系到設備運行安全、維護成本優化和能源效率提升。RUL預測算法能夠提前量化電池剩余可用時間&#x…

PEFT QLora Deepspeed Zero Stage 3 Offload Trainning

使用 accelerate deepspeed zero stage 3 offload 進行 sft trainning 的自動設備映射: GPU 訓練計算 CPU 存儲 run_peft_qlora_deepspeed_stage3.sh #!/bin/bashexport MAX_JOBS4 export OMP_NUM_THREADS4 export disable_exllamaTrue export CUDA_VISIBLE_DEVICES0,1 expor…

JAVA上門家政維修服務系統源碼微信小程序+微信公眾號+APP+H5

一、功能介紹用戶端:精準分類、支持家政、維修、萬能服務、一口價、報價、線上、各類家政服務、優惠專區、師傅入駐、商家入駐、我的需求、補費明細、我的投訴;師傅端:接單池、消息通知、接單管理、今日訂單、師傅入駐、我的錢包、實名認證&a…

GCKontrol對嵌入式設備FPGA設計流程的高效優化

1 前言FPGA(Field-Programmable Gate Array,現場可編程邏輯門陣列)是一種可編程的半導體器件,因其硬件可重構性、硬件并行計算能力、低延遲和實時性的優勢,廣泛應用于數字電路設計、原型驗證和系統加速等領域。但開發…

DBAPI免費版對比apiSQL免費版

DBAPI簡介 零代碼開發api服務,只需編寫sql,就可以生成http api服務。支持api動態創建,兼容多種數據庫。 適用于BI報表、數據可視化大屏的后端接口快速開發。 旨在為企業數據服務的發布提供完整解決方案 一、DBAPI免費版本支持1個數據源連接支…

CTFHub SSRF通關筆記8:數字IP Bypass 原理詳解與滲透實戰

目錄 一、SSRF 二、數字IP原理 1、IP多進制 (1)十進制整數格式 (Dword / 長整數格式) (2)八進制格式 (Octal IP) (3)十六進制格式 (Hex IP) 2、SSRF繞過 三、滲透實戰 1、打開靶場 2、嘗試127.0.…

C++中雙引號和單引號的區別(全面分析)

我在刷算法題的時候經常遇到,用了 出現警告或者使用" "直接報錯,尤其是在字符串部分(py玩家后遺癥/(ㄒoㄒ)/~~)在詳細了解后總結一下加強記憶。 總的來說在 C 中,雙引號 "" 和單引號 是完全不同…

Ubuntu20.04仿真 |iris四旋翼添加云臺相機詳述

申明: 1、本人使用的是Ubuntu20.04ros1gazeboxtdronepx4的仿真組合 2、為了使傳感器模型和飛機模型解耦合,實現不同平臺對傳感器可直接調用,本系列博文涉及的所有傳感器均不直接添加在相應平臺的sdf當中,而是通過編寫xxx_joint.…

《人工智能AI之機器學習基石》系列 第 16 篇:關聯規則與數據挖掘——“啤酒與尿布”傳奇背后的增長秘密

《人工智能AI之機器學習基石》? 專欄核心理念: 用通俗語言講清楚機器學習的核心原理,強調“洞察+ 技術理解 + 應用連接”,構建一個完整的、富有啟發性的知識體系。 引言:藏在購物車里的“讀心術” 朋友們,歡迎回到我們的AI基石之旅。 在過去的兩次探索中,我們深入…

Spring Boot 的自動配置原理

Spring Boot 的自動配置是其 "約定大于配置" 理念的核心實現,它能自動配置 Spring 應用所需的各種組件,大幅減少手動配置。下面從核心注解、加載流程、條件過濾等方面詳細講解其原理,并結合關鍵源碼說明。一、自動配置的入口&#…

谷歌云平臺(Google Cloud Platform, GCP)介紹(全球領先的云計算服務平臺,為企業和開發者提供包括計算、存儲、數據分析、人工智能、機器學習、網絡和安全等在內的全面云服務)

文章目錄**1. GCP的核心優勢****1.1 全球領先的基礎設施****1.2 強大的數據分析和人工智能能力****1.3 卓越的安全性和合規性****1.4 靈活的定價模式****2. GCP的主要服務****2.1 計算服務****2.2 存儲和數據庫****2.3 網絡服務****2.4 人工智能與大數據****2.5 安全與管理工具…

RISC-V異常機制和異常定位

不少人在調試RISC-V core時,面對異常的出現不知所措,不知道如何定位代碼問題。這里將從RISC-V異常機制以及幾個異常實例學習下。 1 異常機制 1.1 什么是異常 異常是軟件程序員不得不要深入了解的,首先在學習異常機制前,對異常要…

c++中導出函數調用約定為__stdcall類型函數并指定導出函數名稱

開發環境在Visual studio 2022版本下,為防止編譯器重命名函數名稱(會加上8等等亂七八糟的東西),我們對函數名稱進行指定:一、新建.def文件,名稱須與dll名稱相同,并放在與cpp文件相同文件夾下&am…

Vision Transformer (ViT) :Transformer在computer vision領域的應用(二)

METHOD,論文主要部分 In model design we follow the original Transformer (Vaswani et al., 2017) as closely as possible. An advantage of this intentionally simple setup is that scalable NLP Transformer architectures – and their efficient implementations –…

AI 論文周報丨紅隊測試語言模型/多視角 3D 點追蹤方法/蛋白質表示學習框架/密碼學漏洞檢測新框架……

近年來,已有若干方法嘗試從單目視頻實現 3D 點跟蹤,然而由于在遮擋和復雜運動等挑戰性場景中難以準確估計 3D 信息,這些方法的性能仍難以滿足實際應用對高精度與魯棒性的要求。 基于此,蘇黎世聯邦理工學院、卡內基梅隆大學聯合提出…

STM32 通過USB的Mass Storage Class讀寫掛載的SD卡出現卡死問題

問題描述:使用stm32cubemx生成的sdio和usb Mass Storage Class的代碼后,在USB_DEVICE\App\usbd_storage_if.c文件里面的接口調用以下函數出現卡死問題: SD_Driver.disk_initialize(0); SD_Driver.disk_read(lun, buf, blk_addr, blk_len) SD_…

Go語言中 error 接口與自定義錯誤類型的深入解析

在 Go 語言開發中,我們經常需要處理各種錯誤情況。Go 語言通過 error 接口提供了一套簡潔而強大的錯誤處理機制。然而,當涉及到自定義錯誤類型時,許多開發者會遇到一些令人困惑的問題。本文將通過一個實際案例來深入探討這個問題。 問題背景 …

字幕編輯工具推薦,Subtitle Edit v4.0.13發布:增強語音識別+優化翻譯功能

大家好呀,不知道大家有沒有做自媒體相關工作的呢,你們是不是也覺得剪輯視頻時最頭疼的往往不是畫面而是字幕,時間軸對不上、格式不兼容、需要手動翻譯,這些瑣碎工作消耗的精力甚至超過剪輯本身。 當你試遍各種在線工具卻發現要么…

【Java后端】Spring Boot 集成雪花算法唯一 ID

Spring Boot 實現基于雪花算法的分布式唯一 ID 生成器在分布式系統中,我們經常需要生成 全局唯一 ID,比如用戶 ID、訂單號、消息 ID 等。常見的方式有:數據庫自增主鍵、UUID、Redis/Zookeeper 分布式 ID 服務、百度 UidGenerator、美團 Leaf …

C語言初嘗試——洛谷

一、C數組:C 語言支持數組數據結構,它可以存儲一個固定大小的相同類型元素的順序集合。數組是用來存儲一系列數據,但它往往被認為是一系列相同類型的變量。聲明數組在 C 中要聲明一個數組,需要指定元素的類型和元素的數量&#xf…