03-netty基礎-多路復用select、poll、epoll

1 什么是多路復用

????????多路復用(Multiplexing)?是一種讓單個線程同時處理多個 I/O 通道的技術,核心是通過系統調用將 I/O 狀態查詢的工作交給操作系統內核,應用程序只需等待內核通知哪些通道就緒。

  • 多路:指的是多個socket網絡連接
  • 復用:指的是復用一個線程,使用一個線程來檢查多個文件描述符(Socket)的就緒狀態
  • 多路復用主要使用的是三種技術:select、poll、epoll。epoll是最新的,也是目前最好的多路復用

2 三種模式的對比

特性selectpollepoll
數據結構固定大小位圖(FD_SETSIZE)動態鏈表紅黑樹 + 就緒鏈表
FD 數量限制通常 1024無限制無限制
事件通知機制遍歷所有 FD遍歷所有 pollfd回調函數直接加入就緒列表
時間復雜度O(n)O(n)O(1)
用戶 / 內核空間復制每次調用復制整個 FD 集合每次調用復制整個 pollfd 數組僅注冊時需要復制
觸發模式僅支持水平觸發(LT)僅支持水平觸發(LT)支持水平觸發(LT)和邊緣觸發(ET)

3 select

3.1 基本概念

select 是 Linux 系統中最早的 I/O 多路復用機制,它使用位圖(fd_set)來表示要監控的文件描述符集合。用戶空間調用 select 方法后,通過系統調用進入內核,內核會遍歷位圖中設置為 1 的每一位,對每個對應的文件描述符調用其 poll 方法來檢查是否有數據可讀、可寫或發生異常。當有事件就緒時,內核會將結果位圖拷貝回用戶空間,用戶程序通過檢查結果位圖來確定哪些文件描述符發生了事件

3.2 實現機制

  • 數據結構:使用固定大小的位圖(bitmap)存儲文件描述符集合,默認最大支持 1024 個 FD。
  • 調用流程
    1. 用戶程序創建 fd_set 并添加關注的 FD
    2. 調用?select()?將 fd_set 從用戶空間復制到內核空間
    3. 內核遍歷所有 FD,檢查是否有就緒事件
    4. 將就緒狀態寫入 fd_set 并復制回用戶空間
    5. 用戶程序遍歷 fd_set 檢查哪些 FD 就緒
  • 關鍵缺點
    • FD 數量限制(通常 1024)
    • 每次調用需復制整個 fd_set
    • 遍歷檢查就緒狀態的時間復雜度為 O (n)

3.3?select源碼分析

3.3.1 關鍵數據結構

// include/uapi/asm-generic/select.h
typedef struct {unsigned long fds_bits[__FD_SETSIZE / (8 * sizeof(long))];
} fd_set;// fs/select.c
struct fdtable {unsigned int max_fds;     // 最大文件描述符數fd_set *open_fds;         // 打開的文件描述符集合fd_set *close_on_exec;    // 執行exec時關閉的集合fd_set *reserve_fds;      // 保留集合
};

3.3.2 核心調用鏈

sys_select()              // 用戶調用的系統調用-> core_sys_select()    // 核心處理函數-> do_select()        // 執行select邏輯-> poll_initwait()  // 初始化等待隊列-> f_op->poll()     // 調用每個文件描述符的poll方法-> __pollwait()     // 將當前進程添加到等待隊列-> check_events()   // 檢查事件是否就緒

3.3.3?do_select 核心邏輯

// fs/select.c
int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time)
{// 初始化等待隊列poll_initwait(&table);// 遍歷所有文件描述符for (i = 0; i < n; i++) {// 獲取文件描述符的poll方法const struct file_operations *f_op = file->f_op;if (f_op && f_op->poll) {// 調用驅動的poll方法,檢查事件并注冊回調wait_key_set(wait, in, out, exc);mask = (*f_op->poll)(file, wait);}}// 如果沒有就緒事件,進入睡眠if (!retval) {retval = poll_schedule_timeout(&table, TASK_INTERRUPTIBLE,to, slack);}// 清理并返回就緒描述符數量poll_freewait(&table);return retval;
}

3.4? 優缺點

  • 優點
    • 跨平臺支持(幾乎所有操作系統都實現了 select)
    • 實現簡單,易于理解
  • 缺點
    • FD 數量限制(通常 1024)
    • 每次調用需復制整個 FD 集合,開銷大
    • 遍歷檢查就緒狀態的時間復雜度為 O (n),性能隨 FD 數量增長而下降

4 poll

4.1 基本概念

poll 的機制與 select 類似,本質上沒有太大差別,也是用于管理多個描述符并進行輪詢,根據描述符的狀態進行處理。它使用 pollfd 結構來描述文件描述符集合,相比 select,poll 沒有最大文件描述符數量的限制。

4.2?實現機制

  • 數據結構:使用鏈表代替固定大小的位圖,每個節點包含 FD、關注事件和就緒事件。
  • 調用流程
    1. 用戶程序創建 pollfd 數組并填充 FD 和關注事件
    2. 調用?poll()?將 pollfd 數組從用戶空間復制到內核空間
    3. 內核遍歷所有 pollfd 檢查就緒狀態
    4. 將就緒事件寫入 revents 字段并復制回用戶空間
    5. 用戶程序遍歷 pollfd 數組檢查就緒事件
  • 改進點:取消了 FD 數量限制,采用鏈表存儲 FD 可動態擴展。
  • 未解決的問題:仍需復制整個 pollfd 數組,遍歷檢查時間復雜度仍為 O (n)。

4.3?poll源碼分析

4.3.1 關鍵數據結構

// include/uapi/linux/poll.h
struct pollfd {int fd;         // 文件描述符short events;   // 關注的事件short revents;  // 就緒的事件
};

4.3.2?核心函數調用鏈

sys_poll()                // 用戶調用的系統調用-> do_sys_poll()        // 核心處理函數-> poll_initwait()    // 初始化等待隊列-> do_poll()          // 執行poll邏輯-> f_op->poll()     // 調用每個文件描述符的poll方法-> __pollwait()     // 將當前進程添加到等待隊列

4.3.3??do_poll 核心邏輯

// fs/select.c
static int do_poll(unsigned int nfds,  struct poll_list *list,struct timespec64 *end_time)
{// 遍歷所有pollfdfor (;;) {struct poll_list *walk;int fdcount = 0;// 遍歷每個pollfdfor (walk = list; walk != NULL; walk = walk->next) {struct pollfd * pfd, * pfd_end;pfd = walk->entries;pfd_end = pfd + walk->len;for (; pfd != pfd_end; pfd++) {// 獲取文件描述符的poll方法if (file->f_op && file->f_op->poll) {// 調用驅動的poll方法mask = file->f_op->poll(file, wait);}// 檢查事件是否匹配if ((mask & pfd->events) &&!test_and_set_bit(pfd->fd, bitmap))fdcount++;}}// 如果有就緒事件或超時,返回if (fdcount || timed_out || signal_pending(current))break;// 否則繼續睡眠fdcount = poll_schedule_timeout(&table, TASK_INTERRUPTIBLE,to, slack);}return fdcount;
}

4.4 ?優缺點

  • 優點
    • 取消了 FD 數量限制
    • 采用動態鏈表存儲 FD,可擴展性更好
  • 缺點
    • 仍需復制整個 pollfd 數組
    • 遍歷檢查時間復雜度仍為 O (n),不適合大量連接場景

5 epoll

5.1 基本概念

epoll 是 Linux 內核為處理大批量文件描述符而改進的 poll,是 select/poll 的增強版本。它基于事件驅動,使用一個文件描述符管理多個描述符,將用戶關心的文件描述符的事件存放到內核的一個事件表中。

5.2 實現機制

  • 核心數據結構
    • 紅黑樹:存儲注冊的 FD,支持 O (log n) 的插入、刪除和查找操作
    • 就緒鏈表:存儲就緒的 FD,通過事件回調機制直接加入
  • 三個核心系統調用
    1. epoll_create:創建一個新的 epoll 實例,并返回一個文件描述符 epfd,用于在 epoll 實例上執行后續操作。
    2. epoll_ctl:用于向 epoll 實例中添加、修改或刪除文件描述符,需要 epfd、操作類型(如 EPOLL_CTL_ADD、EPOLL_CTL_MOD、EPOLL_CTL_DEL)、要操作的文件描述符 fd 和指定感興趣的事件類型 event 這幾個參數
    3. epoll_wait:等待 epoll 實例中的 I/O 事件到達,它監視由 epoll_ctl 添加的文件描述符上的事件,需要 epfd 和用于存儲就緒事件的數組,以及可選的超時時間。
  • 關鍵優化
    • 使用事件回調機制,無需遍歷所有 FD
    • 通過內存映射技術減少用戶 / 內核空間的數據復制
    • 高效的 FD 管理,紅黑樹支持大規模連接

epoll 內核實現原理中,有紅黑樹用于記錄用戶程序注冊的 epoll 事件,等待隊列用于喚醒 epoll 線程,就緒隊列用于記錄 socket 讀事件和寫事件。其流程如下:

  1. 用戶程序調用 epoll_create 函數后,在內核創建 struct eventpoll 對象,同時返回一個文件描述符給用戶。
  2. 用戶程序通過 epoll_ctl 函數添加、修改、刪除 socket 事件,注冊成功的 socket 事件會插入紅黑樹。
  3. 如果 epoll 就緒隊列有就緒事件,用戶程序調用 epoll_wait 函數會成功獲取到就緒事件;如果沒有就緒事件,則 epoll 線程陷入休眠。
  4. 當 socket 接收到數據后,通過 socket 等待隊列可以喚醒休眠的 epoll 線程,并將 socket 封裝成 epoll 就緒事件插入就緒隊列,epoll 線程將就緒事件拷貝至用戶程序。

5.3?epoll源碼分析

5.3.1 關鍵數據結構

// include/linux/epoll.h
struct eventpoll {spinlock_t lock;                // 自旋鎖struct mutex mtx;               // 互斥鎖wait_queue_head_t wq;           // 等待隊列頭wait_queue_head_t poll_wait;    // poll方法的等待隊列struct list_head rdllist;       // 就緒描述符鏈表struct rb_root rbr;             // 紅黑樹根節點struct epitem *ovflist;         // 溢出鏈表
};struct epitem {struct rb_node rbn;             // 紅黑樹節點struct list_head rdllink;       // 就緒鏈表節點struct epoll_filefd ffd;        // 文件描述符信息struct eventpoll *ep;           // 所屬的eventpoll對象struct list_head fllink;        // 文件的epitem鏈表struct epoll_event event;       // 用戶關注的事件
};

5.3.2?核心函數調用鏈

// epoll_create 相關
sys_epoll_create()-> epoll_create1()-> epi = kmem_cache_alloc(epi_cache, GFP_KERNEL);  // 創建epitem-> init_poll_funcptr(&epi->pt, ep_ptable_queue_proc);  // 初始化poll函數指針// epoll_ctl 相關
sys_epoll_ctl()-> ep_insert()      // 添加文件描述符-> ep_modify()     // 修改事件-> ep_delete()     // 刪除文件描述符// epoll_wait 相關
sys_epoll_wait()-> ep_poll()-> ep_events_available()  // 檢查是否有就緒事件-> fetch_events()         // 將就緒事件從rdllist復制到用戶空間-> schedule_hrtimeout_range()  // 沒有事件時進入睡眠

5.3.3??ep_poll 核心邏輯

// epoll_create 相關
sys_epoll_create()-> epoll_create1()-> epi = kmem_cache_alloc(epi_cache, GFP_KERNEL);  // 創建epitem-> init_poll_funcptr(&epi->pt, ep_ptable_queue_proc);  // 初始化poll函數指針// epoll_ctl 相關
sys_epoll_ctl()-> ep_insert()      // 添加文件描述符-> ep_modify()     // 修改事件-> ep_delete()     // 刪除文件描述符// epoll_wait 相關
sys_epoll_wait()-> ep_poll()-> ep_events_available()  // 檢查是否有就緒事件-> fetch_events()         // 將就緒事件從rdllist復制到用戶空間-> schedule_hrtimeout_range()  // 沒有事件時進入睡眠

5.4 ?優缺點

  • 優點
    • 無 FD 數量限制,可輕松處理數萬甚至數十萬個連接
    • 事件驅動機制,時間復雜度 O (1),性能不會隨 FD 數量增長而下降
    • 使用內存映射技術減少數據復制,效率高
    • 支持邊緣觸發(ET)模式,減少不必要的系統調用
  • 缺點
    • 僅 Linux 系統支持,不跨平臺
    • 編程模型相對復雜,邊緣觸發模式需要更嚴謹的編程邏輯

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

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

相關文章

網易大模型算法面經總結第一篇

網友一 MHA的原理&#xff0c;是如何進行加速的&#xff0c;用的什么框架推理。 回答&#xff1a; ①先答一下什么是MHA&#xff1a;Multi-Head Attention&#xff08;MHA&#xff09;是 Transformer 的核心機制&#xff0c;并行地關注輸入序列中不同位置的多種信息 ②回答MHA的…

Vue3 面試題及詳細答案120道(91-105 )

《前后端面試題》專欄集合了前后端各個知識模塊的面試題&#xff0c;包括html&#xff0c;javascript&#xff0c;css&#xff0c;vue&#xff0c;react&#xff0c;java&#xff0c;Openlayers&#xff0c;leaflet&#xff0c;cesium&#xff0c;mapboxGL&#xff0c;threejs&…

SAP-MM-物料進銷存表

ABAP庫存進銷存報表程序摘要 該ABAP程序是一個完整的庫存進銷存報表系統,主要功能包括: 報表類型選擇: 物料庫存進銷存 批次庫存進銷存 寄售庫存進銷存 供應商庫存進銷存 原料庫存進銷存 主要功能: 從歷史數據表(MARDH, MSKAH, MSLBH, MCHBH等)獲取期初庫存 處理物料移動數…

這幾天都是發癲寫的

#include <iostream> #include <vector> #include <unordered_map> #include <algorithm> #include <cmath> // for sqrt// Gen-Sort 實現&#xff08;保持不變&#xff09; void genSort(std::vector<int>& arr) {if (arr.empty()) r…

QT6 源,七章對話框與多窗體(11) 進度對話框 QProgressDialog:屬性,公共成員函數,槽函數,信號函數,與源代碼帶注釋

&#xff08;1&#xff09; 本類的繼承關系 &#xff1a;可見&#xff0c;進度對話框&#xff0c;也是 QDialog 的子類&#xff0c;在其上面又擺放了一些控件&#xff0c;構成了不同用途的對話框。咱們也可以自定義對話框。只是沒有 QT 官方大師們做的好。 人家在定義這 6 個子…

學習游戲制作記錄(技能系統)7.24

1.技能系統概念首先讓我們了解一下游戲的技能本質是什么&#xff0c;以投擲劍為例子&#xff0c;當玩家使用這個技能時&#xff0c;首先會播放玩家的動畫&#xff0c;隨后通過技能腳本創建一個劍的對象&#xff0c;當劍回收時會再次調用腳本&#xff0c;讓它朝向玩家飛來并銷毀…

外部存檔(External Archive)機制

前言 提醒&#xff1a; 文章內容為方便作者自己后日復習與查閱而進行的書寫與發布&#xff0c;其中引用內容都會使用鏈接表明出處&#xff08;如有侵權問題&#xff0c;請及時聯系&#xff09;。 其中內容多為一次書寫&#xff0c;缺少檢查與訂正&#xff0c;如有問題或其他拓展…

MybatisPlus操作方法詳細總結

摘要&#xff1a;本文圍繞 MyBatis-Plus 數據操作展開&#xff0c;涵蓋標準數據層 CRUD 與分頁查詢&#xff1b;以及各種的復雜 SQL 查詢&#xff1b;映射匹配&#xff08;TableField、TableName 注解&#xff09;與 ID 生成策略&#xff08;TableId 五種類型及全局配置&#x…

【C語言進階】動態內存管理的面試題||練習

本節內容專門整理了一些動態內存管理的面試題&#xff0c;配有詳細的解答。 目錄 1. 看代碼說結果 2. 看代碼說結果 3. 看代碼說結果 4.小樂樂與歐幾里得 描述 分析1&#xff1a; 分析2&#xff1a; 代碼&#xff1a; 5. 空心正方形 分析&#xff1a; 1. 看代碼說結…

【圖論】倍增與lca

void dfs(long u,long father){ dep[u]dep[father]1;//只在這里初始化depfor(long i1;(1<<i)<dep[u];i)fa[u][i]fa[fa[u][i-1]][i-1];//只這里用的倍增for(long ihead[u];~i;iedge[i].next){long vedge[i].to;if(vfather)continue;fa[v][0]u;dfs(v,u); }} long lca(lo…

VS Code 美化插件

目錄1. Better Comments 更好的注釋2. indent-rainbow 彩虹的縮進3. Trailing Spaces 尾隨的空格4. Gruvbox Material 護眼的材質5. Md Editor 博客編輯器6. 待補充推薦筆記&#xff1a;VS Code寫代碼必備的五款代碼美化插件 1. Better Comments 更好的注釋 Better Comments Be…

火語言 RPA 在日常運維中的實踐

在系統運維和技術支持工作中&#xff0c;總有一些操作像 “固定程序” 一樣循環往復&#xff1a;定期檢查服務器狀態、批量處理用戶權限申請、手動清理系統日志…… 這些工作步驟固定、邏輯簡單&#xff0c;卻占用了大量本可用于故障排查和系統優化的時間。近期在優化運維團隊的…

FOUPK3system5XOS系統 NTX V2.0發布通知

FOUPK3system5XOS系統NTX V2.0發布通知更新1.系統安全&#xff1a;使用FOUPK3system5XOS NOS X9新內核與FOUPK3system5XOS系統19.63正式版一樣提供更好的安全性2.原生應用&#xff1a;啟用FOUPK3system5XOS ONS X9 API 72服務FOUPK3system5XOS系統 NTX V2.0用戶支持使用FOUPK3…

爬蟲算法原理解析

文章目錄 核心算法原理 1. 圖遍歷算法 廣度優先搜索(BFS) 深度優先搜索(DFS) 2. URL調度算法 優先級隊列調度 3. 頁面去重算法 基于哈希的去重 基于布隆過濾器的去重 4. 鏈接提取與規范化 5. 抓取頻率控制算法 6. 增量爬取算法 高級算法策略 1. PageRank算法在爬蟲中的應用 2. …

探索雙鏈表:C語言中的鏈式結構魔法

目錄 引言 一、雙鏈表基礎 1.1、什么是雙鏈表&#xff1f; 1.2、雙鏈表節點的結構定義 二、雙鏈表的基本操作 2.1、雙鏈表的初始化 2.2、尾插法 2.3、頭插 2.4、判斷雙鏈表是否為空 2.5、尾刪法 2.6、頭刪法 2.7、查找 2.8、雙鏈表在指定位置之前插入 2.9、雙鏈表…

HTML5 + CSS3模擬西門慶、武大郎和潘金蓮的精彩520微信聊天,看完我又相信愛情了

今天520了&#xff0c;我用HTML5 CSS3模擬了西門慶、武大郎和潘金蓮的精彩微信聊天&#xff0c;希望你看完以后可以在緊張的工作中&#xff0c;放松一下&#xff0c;開心一下&#xff0c;同時祝你在這個520可以過得開心快樂。 目錄 1 實現思路 1.1 聊天實現素材 1.2 HTML布…

【Linux】Linux了解與基本指令(1)

hello~ 很高興見到大家! 這次帶來的是C中關于Linux基本指令這部分的一些知識點,如果對你有所幫助的話,可否留下你寶貴的三連呢? 個 人 主 頁: 默|笙 文章目錄一、認識Linux二、操作系統&#xff08;OS&#xff09;三、基本指令1. 目錄與普通文件1.1 目錄1.2 普通文件2. pwd 與…

dify 學習筆記

目錄 啟動項目 瀏覽器訪問&#xff1a; dify刪除工作流 代碼是開源dify 啟動項目 cd E:\project\qwen\dify-main\docker docker compose up -d 瀏覽器訪問&#xff1a; http://127.0.0.1/apps dify刪除工作流 右下角&#xff0c;三個點&#xff0c;點擊彈出框&#xff0…

【YOLOv8改進 - 特征融合】FCM:特征互補映射模塊 ,通過融合豐富語義信息與精確空間位置信息,增強深度網絡中小目標特征匹配能力

YOLOv8目標檢測創新改進與實戰案例專欄 專欄目錄: YOLOv8有效改進系列及項目實戰目錄 包含卷積,主干 注意力,檢測頭等創新機制 以及 各種目標檢測分割項目實戰案例 專欄鏈接: YOLOv8基礎解析+創新改進+實戰案例 文章目錄 YOLOv8目標檢測創新改進與實戰案例專欄 介紹 摘要 文…

算法訓練營day30 貪心算法④ 重疊問題 452. 用最少數量的箭引爆氣球、435. 無重疊區間 、 763.劃分字母區間

貪心算法的第四篇博客&#xff0c;主要是重疊問題的練習&#xff0c;思路都較為簡單&#xff0c;最后一題可能需要著重思考一下 452. 用最少數量的箭引爆氣球 遍歷數組&#xff0c;如果存在重疊則減少一支箭&#xff08;不重疊則增加一支箭&#xff09; 重疊的判定&#xff1a…