Linux 系統 poll 與 epoll 機制2:實現原理與應用實踐

接上文poll機制:Linux 系統 poll 與 epoll 機制1。

3. epoll 機制:高并發 I/O 的優化實現?

epoll(Efficient event polling implementation)機制誕生于 Linux 2.5.44 版本,是內核為解決高并發 I/O 場景(如萬級以上 FD 監聽)而設計的新一代 I/O 多路復用技術。epoll全稱event poll,但其中的e有double e的味道:efficient & event。它通過紅黑樹管理注冊 FD、就緒鏈表存儲就緒 FD、內存映射(mmap)減少拷貝三大優化,徹底解決了poll的性能瓶頸,實現了 “O (1) 就緒事件查詢”,成為高性能服務器的標配。?

3.1 epoll 的核心接口與數據結構?

3.1.1 三大核心系統調用?

epoll 通過三個獨立的系統調用來實現 “FD 注冊 - 事件監聽 - 就緒查詢” 的完整流程,避免了poll每次調用都需重新傳遞 FD 集合的問題。epool是anon_inode技術的一個應用案例。

  1. epoll_create():創建一個 epoll 實例(內核的核心數據結構);?

  2. epoll_ctl():向 epoll 實例中添加、修改或刪除需監聽的 FD 及其事件;?

  3. epoll_wait():等待 epoll 實例中注冊的 FD 就緒,并返回就緒事件。?

3.1.2 關鍵數據結構?

epoll 的內核實現依賴三個核心數據結構:struct eventpoll、struct epitem、struct epoll_event。?

(1)用戶空間的struct epoll_event?

用戶進程通過該結構體與內核交互,描述 FD 的監聽事件和就緒狀態,定義如下:

#include <sys/epoll.h>?
struct epoll_event {?uint32_t events;  // 監聽事件/就緒事件(與poll的events含義類似)?epoll_data_t data; // 關聯的用戶數據(如FD、自定義指針)?
};?
?
// 聯合體,存儲用戶數據?
typedef union epoll_data {?void    *ptr;    // 自定義指針(可指向用戶空間數據)?int      fd;     // 關聯的文件描述符?uint32_t u32;    // 32位無符號整數?uint64_t u64;    // 64位無符號整數?
} epoll_data_t;

與pollfd相比,epoll_event的優勢是通過epoll_data_t聯合體支持自定義數據,方便用戶進程關聯 FD 的上下文信息(如客戶端連接的會話數據)。?

(2)內核中的struct epitem?

epitem是內核中描述 “epoll 實例與 FD 關聯關系” 的結構,每個注冊到 epoll 的 FD 對應一個epitem,定義簡化如下:

struct epitem {?struct rb_node rbn;          // 紅黑樹節點(用于加入epoll實例的紅黑樹)?struct list_head rdllink;    // 就緒鏈表節點(FD就緒時加入就緒鏈表)?struct file *file;           // 關聯的FD對應的struct file?struct epoll_event event;    // 存儲用戶設置的監聽事件與用戶數據?struct epoll_table_struct *epoll_table; // 關聯的poll_table?
};
  • rbn:用于將epitem插入 epoll 實例的紅黑樹,實現 FD 的快速查找、插入、刪除;?

  • rdllink:用于 FD 就緒時,將epitem插入 epoll 實例的就緒鏈表,避免遍歷所有 FD;?

  • epoll_table:關聯poll_table,用于將進程注冊到 FD 的等待隊列。?

(3)內核中的struct eventpoll?

eventpoll是 epoll 實例的核心結構,每個epoll_create()調用會創建一個eventpoll,該對象是內核對象通過anon_inode技術供用戶態訪問。定義簡化如下:

struct eventpoll {?spinlock_t lock;             // 保護紅黑樹和就緒鏈表的自旋鎖?struct rb_root rbr;          // 紅黑樹的根節點(管理所有注冊的epitem)?struct list_head rdllist;    // 就緒鏈表的頭節點(存儲所有就緒的epitem)?wait_queue_head_t wq;        // epoll的等待隊列(存儲調用epoll_wait的進程)?struct page *tmp_page;       // 用于mmap的內存頁(減少用戶態與內核態拷貝)?
};
  • rbr:紅黑樹的根,用于管理所有通過epoll_ctl注冊的epitem,紅黑樹的 key 是 FD,確保插入、刪除、查找的時間復雜度為 O (logn);?

  • rdllist:就緒鏈表,存儲所有就緒的epitem,epoll_wait只需遍歷該鏈表即可獲取就緒 FD,無需遍歷所有注冊 FD;?

  • wq:epoll 的等待隊列,當無 FD 就緒時,調用epoll_wait的進程會睡眠在該隊列中,FD 就緒時被喚醒;?

  • tmp_page:通過mmap將內核內存頁映射到用戶空間,避免epoll_event數組的拷貝。

3.2 epoll 的核心流程(基于 ET 模式)?

epoll 支持兩種觸發模式:水平觸發(Level Trigger,LT) 和邊緣觸發(Edge Trigger,ET)。LT 模式與poll類似,只要 FD 就緒,每次調用epoll_wait都會返回該 FD;ET 模式僅在 FD 狀態從 “未就緒” 變為 “就緒” 時返回一次,需配合非阻塞 I/O 使用,避免漏讀數據。以下以 ET 模式為例,拆解 epoll 的核心流程。?

3.2.1 步驟 1:創建 epoll 實例(epoll_create)?

用戶進程調用epoll_create(size_t size)(注:size參數在 Linux 2.6.8 后被忽略,僅用于兼容舊版本),內核會:?

  1. 分配一個struct eventpoll結構體;?

  2. 初始化結構體中的紅黑樹(rbr)、就緒鏈表(rdllist)、等待隊列(wq);?

  3. 分配一個內存頁(tmp_page),用于后續mmap;?

  4. 創建一個匿名文件(內核內部使用),并返回一個epoll 文件描述符(epfd),用戶進程通過epfd操作該 epoll 實例。?

3.2.2 步驟 2:注冊 FD 到 epoll 實例(epoll_ctl)?

用戶進程調用epoll_ctl(int epfd, int op, int fd, struct epoll_event *event),其中op為操作類型(EPOLL_CTL_ADD:添加、EPOLL_CTL_MOD:修改、EPOLL_CTL_DEL:刪除),內核會:?

  1. 通過epfd找到對應的eventpoll結構體;?

  2. 根據op類型執行對應操作。

OP操作
EPOLL_CTL_ADD(添加 FD)

a. 檢查fd是否已注冊(通過紅黑樹查找epitem),若已注冊則返回錯誤;?

b. 分配一個struct epitem結構體,初始化rbn(紅黑樹節點)、rdllink

(就緒鏈表節點),并關聯fd對應的struct file和用戶傳入的event;?

c. 將epitem插入eventpoll的紅黑樹(rbr);?

EPOLL_CTL_MOD(修改 FD)

a. 通過紅黑樹查找fd對應的epitem;?

b. 更新epitem中的event字段(如修改監聽事件);?

c. 重新調用設備poll方法,更新等待隊列注冊。?

d. 調用fd對應的設備poll方法,傳遞epoll_table(由epitem關聯),

將當前進程注冊到fd的等待隊列中(若后續fd就緒,會觸發喚醒邏輯)。?

EPOLL_CTL_DEL(刪除 FD)

a. 通過紅黑樹查找fd對應的epitem;?

b. 將epitem從紅黑樹和就緒鏈表中移除;?

c. 調用設備poll方法,將進程從fd的等待隊列中刪除;?

d. 釋放epitem結構體。?

3.2.3 步驟 3:等待 FD 就緒(epoll_wait)?

用戶進程調用epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout),其中events是用戶空間存儲就緒事件的數組,maxevents是數組長度,內核會:?

  1. 通過epfd找到eventpoll結構體,并加鎖(spinlock);?

  2. 檢查就緒鏈表(rdllist)是否為空:?

  • 若非空:遍歷就緒鏈表,將每個epitem的event(含就緒事件和用戶數據)拷貝到events數組中,最多拷貝maxevents個元素;?

  • 若為空:判斷timeout值,若timeout > 0,則將當前進程睡眠在eventpoll的等待隊列(wq)中,直到 FD 就緒、超時或被信號中斷;若timeout = 0,直接返回 0;若timeout = -1,無限等待。

? ? ? ?3.??解鎖并返回就緒事件的數量(若超時返回 0,失敗返回 - 1)。?

3.2.4 步驟 4:FD 就緒與進程喚醒?

當某個注冊的 FD 就緒時(如 TCP socket 收到數據),內核會:?

  1. 觸發 FD 所屬設備的中斷處理函數(如網絡中斷);?

  2. 中斷處理函數調用 FD 的poll方法,判斷 FD 狀態并標記為就緒;?

  3. 找到該 FD 對應的epitem(通過struct file關聯),將epitem加入eventpoll的就緒鏈表(rdllist);?

  4. 遍歷eventpoll的等待隊列(wq),喚醒所有睡眠在該隊列中的進程(即調用epoll_wait的進程);?

  5. 進程被喚醒后,重新執行epoll_wait的邏輯,遍歷就緒鏈表并返回就緒事件。?

3.2.5 步驟 5:用戶進程處理 I/O 事件?

用戶進程通過events數組獲取就緒 FD 后,需:?

  1. 檢查每個就緒 FD 的events字段(如POLLIN),確定事件類型;?

  2. 由于 ET 模式僅通知一次,需通過非阻塞 I/O(如read時設置O_NONBLOCK)循環讀取 / 寫入數據,直到返回EAGAIN(無更多數據可讀 / 寫);?

  3. 處理完數據后,可繼續調用epoll_wait等待下一次事件。?

3.3 epoll 的效率優化關鍵點?

epoll 相比poll的性能優勢,源于四個核心優化:?

  • 紅黑樹管理注冊 FD:O (logn) 的操作復雜度?

poll每次調用都需遍歷所有 FD,時間復雜度為 O (n);而 epoll 通過紅黑樹管理注冊的 FD,插入、刪除、查找的時間復雜度均為 O (logn),即使 FD 數量達到 10 萬級,操作耗時也可忽略。?

  • 就緒鏈表存儲就緒 FD:O (1) 的就緒查詢?

poll需遍歷所有 FD 才能判斷是否就緒,而 epoll 在 FD 就緒時主動將其加入就緒鏈表,epoll_wait只需遍歷就緒鏈表即可獲取就緒 FD,時間復雜度為 O (k)(k 為就緒 FD 數量),當大多數 FD 未就緒時(高并發場景常見),效率提升極為顯著。?

  • mmap 減少用戶態與內核態拷貝?

poll每次調用都需拷貝struct pollfd數組(用戶態→內核態→用戶態),而 epoll 通過mmap將內核中的tmp_page內存頁映射到用戶空間,epoll_event數組直接在映射內存中傳遞,無需拷貝,大幅減少了數據傳輸開銷。?

  • 邊緣觸發(ET)減少無效通知?

LT 模式下,若用戶進程未完全處理 FD 數據,內核會反復通知該 FD,導致無效系統調用;ET 模式僅在 FD 狀態變化時通知一次,配合非阻塞 I/O 可避免無效通知,減少系統調用次數,進一步提升效率。

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

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

相關文章

Mamba LLM 架構簡介:機器學習的新范式

Mamba LLM 架構簡介&#xff1a;機器學習的新范式探索 Mamba LLM 的強大功能&#xff0c;Mamba LLM 是來自一流大學的變革性架構&#xff0c;重新定義了 AI 中的序列處理。語言模型是一種經過訓練的機器學習模型&#xff0c;用于在自然語言上執行概率分布。它們的架構主要由多層…

GaussDB生產擴容引起的PANIC問題處理案例

1 環境信息CPU:8C內存&#xff1a;64GGaussDB版本&#xff1a;24.7.32解決方案部署形態&#xff1a;HCS部署形態&#xff1a;1主1從1日志擴容原因&#xff1a;當前的配置滿足不了max_connections為2000值&#xff0c;即當前的業務最大連接數超過2000個而按照8C64G的配置最多滿足…

【168頁PPT】華為流程管理體系構建與落地(附下載方式)

篇幅所限&#xff0c;本文只提供部分資料內容&#xff0c;完整資料請看下面鏈接 https://download.csdn.net/download/2501_92796370/91662548 資料解讀&#xff1a;【168頁PPT】華為流程管理體系構建與落地 詳細資料請看本解讀文章的最后內容。華為&#xff0c;作為全球知名…

基于CotSegNet網絡和機器學習的棉花點云器官分割和表型信息提取

一、引言PointNet作為點云處理領域的先驅與里程碑式深度學習模型&#xff0c;以其卓越的性能和對無序點云數據直接處理的能力而聞名。博主將分享1篇發表在《Computers and Electronics in Agriculture》&#xff08;中科院1區TOP&#xff09;的“Organ segmentation and phenot…

經典卷積神經網絡CNN

一、CNN視覺處理三大任務&#xff1a;圖像分類、目標檢測、圖像分割上游&#xff1a;提取特征&#xff0c;CNN下游&#xff1a;分類、目標、分割等&#xff0c;具體的業務1. 概述卷積神經網絡是深度學習在計算機視覺領域的突破性成果。在計算機視覺領域, 往往我們輸入的圖像都很…

11.1.5 實現文件刪除,共享和共享下載排行榜

1、圖床分享圖片api_sharepicture.cc sharepicture_cgi.c 分享后每個人都可以看到。 數據庫&#xff1a; DROP TABLE IF EXISTS share_picture_list; CREATE TABLE share_picture_list (id int(11) NOT NULL AUTO_INCREMENT COMMENT 編號,user varchar(32) NOT NULL COMMENT …

【Java后端】SpringBoot配置多個環境(開發、測試、生產)

在 Spring Boot 中配置多個環境&#xff08;開發、測試、生產&#xff09;通常用 配置文件分環境管理 啟動參數切換 的方式來實現。下面一個完整的實踐指南&#xff1a;&#x1f539; 1. 使用多配置文件管理環境 Spring Boot 默認支持 application-{profile}.properties 或 ap…

HTTP 分塊傳輸編碼:深度解析與報文精髓

分塊傳輸編碼&#xff08;Chunked Transfer Encoding&#xff09;是 HTTP/1.1 協議中的一項核心特性&#xff0c;它允許服務器在不預先知道響應體總大小的情況下&#xff0c;高效地傳輸數據。這項技術解決了傳統 Content-Length 機制的局限性&#xff0c;使得 HTTP 協議能夠完美…

Vue 項目首屏加載速度優化

Vue 項目首屏加載從 5s 到 1.5s&#xff1a;4 步落地優化方案&#xff0c;附完整代碼 數據對比前段時間我在做一個活動時&#xff0c;打包加載后發現打開頁面要等半天&#xff0c;經過幾天的優化&#xff0c;最終將首屏加載時間從5秒壓到 1.5 秒。這篇文章會把整個優化過程拆解…

Java學習第十六部分——JUnit框架

目錄 一.概述 二.作用 三.版本 四.優勢 五.局限性 六.發展方向 七.核心組件 1 測試用例 2.斷言&#xff08;Assertions&#xff09; 3.測試生命周期 4.測試運行器 八.簡單示例 九.JUnit 4 與 JUnit 5 的區別 十.idea項目實戰 1.在idea中創建Java項目&#xff0c…

[吾愛原創] 千千每日計劃

[吾愛原創] 千千每日計劃 鏈接&#xff1a;https://pan.xunlei.com/s/VOYuE8p-KIV-NJr2_0d1Ak9YA1?pwdbqez# 介紹&#xff1a;千千系列的最后一款軟件,一款每日計劃的一款軟件&#xff0c;并且支持時間段修改和打卡和導入導出等功能。 功能&#xff1a; 1.設置每天的計劃 2…

docker命令(二)

目錄 docker命令 1.inspect命令&#xff08;查看鏡像信息&#xff09; 2.tag命令&#xff08;為鏡像起別名&#xff09; 3.--help命令&#xff08;查看命令的使用幫組&#xff09; docker 命令 --help docker --help 4.run命令 1.格式 2.啟動tomcat鏡像 3. docker 不能被外部訪…

Dockerfile實現java容器構建及項目重啟(公網和內網)

公網情況0.Dockerfile關鍵字關鍵字作用一句話出現位置FROM指定基礎鏡像&#xff08;任何 Dockerfile 必須且首行&#xff09;全局RUN在鏡像構建階段執行命令&#xff08;常用來安裝軟件&#xff09;構建期COPY把宿主機文件/目錄復制進鏡像構建期ADD類似 COPY&#xff0c;但額外…

SpringCloud與Dubbo深度對比:架構、性能與生態全解析

引言在微服務架構盛行的今天&#xff0c;服務治理框架的選擇成為企業技術棧決策的關鍵環節。Spring Cloud和Dubbo作為Java生態中最具代表性的兩大微服務框架&#xff0c;各自擁有獨特的優勢和適用場景。本文將從架構設計、服務治理、性能表現、生態系統等多個維度進行深度對比&…

簡歷書寫---自我評價怎么寫

前言 今天一對一輔導了很多同學做簡歷&#xff0c;看到很多同學簡歷上都有一欄&#xff1a;自我評價 那我們就要思考一下&#xff0c;我們搞技術的&#xff0c;一份技術簡歷&#xff0c;自我評價上怎么寫&#xff0c;才能算一個加分點呢&#xff1f; 觀點分享 首先&#xff0c;…

嵌入式Linux學習 - 數據庫開發

目錄 一. 在終端的使用 1. 下載 2. 操作 3. 相關函數 1.增 2. 刪 3. 改 4. 查 5. 補充函數 二. 在軟件的使用 1. 下載 2. 操作 三. 在編程的使用 1. 下載 2. 相關函數 1. 打開 2. 讀寫執行sql語句 3. 關閉 一. 在終端的使用 1. 下載 sudo apt-get install …

產品運營必備的職場通用能力有哪些?如何一步步提升?

在流量紅利消退的存量競爭時代&#xff0c;產品運營崗位正經歷價值重構。單純的活動策劃與用戶維護已無法滿足發展需求&#xff0c;數據驅動的精細化運營成為行業分水嶺。面對這場變革&#xff0c;復合能力建設與前瞻工具掌握是運營人突破天花板的密鑰。推薦考取CDA數據分析師&…

ESPTimer vs GPTimer:ESP32 定時器系統深度解析

第十五章和第十六章分別學習了??ESPTimer?? 和 ??GPTimer?? &#xff0c;那這兩種定時器有什么區別&#xff0c;如何使用呢&#xff0c;下面探討下。1. 兩種定時器對比介紹1.1 兩種定時器設計在 ESP32 開發中&#xff0c;??ESPTimer?? 和 ??GPTimer?? 是兩種完…

【70頁PPT】WMS助力企業數字化轉型(附下載方式)

篇幅所限&#xff0c;本文只提供部分資料內容&#xff0c;完整資料請看下面鏈接 https://download.csdn.net/download/2501_92808811/91806268 資料解讀&#xff1a;【70頁PPT】WMS助力企業數字化轉型 詳細資料請看本解讀文章的最后內容。倉儲管理在企業運營中占據關鍵地位&a…

[光學原理與應用-337]:ZEMAX - 自帶的用于學習的樣例設計

ZEMAX&#xff08;OpticStudio&#xff09;內置了大量樣例設計文件&#xff0c;這些文件覆蓋了從基礎光學原理到復雜系統設計的全場景&#xff0c;是學習光學設計、掌握軟件操作、理解像差理論的絕佳資源。以下是ZEMAX自帶樣例設計的詳細分類、使用方法及學習價值分析&#xff…