IO多路復用

常見的網絡IO模型

網絡 IO 模型分為四種:同步阻塞 IO(Blocking IO, BIO)、同步非阻塞IO(NIO, NewIO)、IO 多路復用、異步非阻塞 IO(Async IO, AIO),其中AIO為異步IO,其他都是同步IO

同步阻塞IO

同步阻塞IO:在線程處理過程中,如果涉及到IO操作,那么當前線程會被阻塞,直到IO處理完成,線程才接著處理后續流程。如下圖,服務器針對客戶端的每個socket都會分配一個新的線程處理,每個線程的業務處理分2步,當步驟1處理完成后遇到IO操作(比如:加載文件),這時候,當前線程會被阻塞,直到IO操作完成,線程才接著處理步驟2。

同步阻塞IO 演示圖

實際使用場景

在Java中使用線程池的方式去連接數據庫,使用的就是同步阻塞IO模型。

模型的缺點

因為每個客戶端存都需要一個新的線程,勢必導致線程被頻繁阻塞和切換帶來開銷。

同步非阻塞 IO-NIO(New IO)

同步非阻塞IO:在線程處理過程中,如果涉及到IO操作,那么當前的線程不會被阻塞,而是會去處理其他業務代碼,然后等過段時間再來查詢 IO 交互是否完成。如下圖:Buffer 是一個緩沖區,用來緩存讀取和寫入的數據;Channel 是一個通道,負責后臺對接 IO 數據;而 Selector 實現的主要功能,是主動查詢哪些通道是處于就緒狀態。Selector復用一個線程,來查詢已就緒的通道,這樣大大減少 IO 交互引起的頻繁切換線程的開銷。

實際使用場景

Java NIO 正是基于這個 IO 交互模型,來支撐業務代碼實現針對 IO 進行同步非阻塞的設計,從而降低了原來傳統的同步阻塞 IO 交互過程中,線程被頻繁阻塞和切換帶的開銷。

NIO使用的經典案例是Netty框架,Elasticsearch底層實際上就是采用的這種機制。

IO多路復用

  • IO多路復用是一種同步IO模型,實現一個線程可以監視多個文件句柄;一旦某個文件句柄就緒,就能夠通知應用程序進行相應的讀寫操作;沒有文件句柄就緒時會阻塞應用程序,交出cpu。多路是指網絡連接,復用指的是同一個線程

?

所以,每個客戶端和服務器的socket 連接就可以看做”一路“,多個客戶端和該服務器的socket連接就是”多路“,從而,IO多路就是多個socket連接上的輸入輸出流,復用就是多個socket連接上的輸入輸出流由一個線程處理。 因此 IO多路復用可以定義如下:

Linux中的 IO多路復用是指:一個線程處理多個IO流

IO多路復用3種實現方式

select/pool/epool

基本socket模型

先看下socket模型,以便與下面幾種實現方式對比:

listenSocket = socket() // 系統調用socket(),創建一個主動socketbind(listenSocket) // 給主動socket綁定地址和端口listen(listenSocket) // 將默認的主動socket轉換為服務器的被動socket(也叫監聽socket)while(true) {connSocket = accept(listenSocket) // 接受客戶端連接,獲取已鏈接socketrecv(connSocket) // 從客戶端讀取數據,只能同時處理一個客戶端send(connSocket) // 往客戶端發送數據,只能同時處理一個客戶端
}

實現網絡通信流程如下圖

?

基礎的socket模型,能夠實現服務器端和客戶端的通信,但程序每調用一次accept函數,只能處理一個客戶端請求,當有大量客戶端連接時,這種模型處理性能較差,因此linux提供了高性能的IO多路復用機制來解決這種困境。

select機制

select是最古老的I/O多路復用機制,可以同時監聽多個文件描述符的讀寫事件。它使用的fd_set數據結構來存儲待監聽的文件描述符集合,并通過select()函數將fd_set集合傳遞給內核,等待內核返回文件描述符的狀態變化。

fd_set數據結構 (bitmap)

typedef struct {unsigned long fds_bits[__FDSET_LONGS];
} fd_set;
/**
*  參數說明
*  監聽的文件描述符數量__nfds、
*  被監聽描述符的三個集合*__readfds,*__writefds和*__exceptfds
*  監聽時阻塞等待的超時時長*__timeout
*  返回值:返回一個socket對應的文件描述符
*/
int select(int __nfds, fd_set * __readfds, fd_set * __writefds, fd_set * __exceptfds, struct timeval * __timeout)

select實現網絡通信流程如下圖:

?缺點

1、select使用的fd_set數據結構對單個進程能監聽的文件描述符是有限制的,默認是1024

2、select()函數返回后,需要遍歷文件描述符集合,才能找到就緒的描述符,遍歷過程會產生一定開銷,降低性能。

poll機制

poll與select類似,也可以同時監聽多個文件描述符的讀寫事件。它使用的pollfd數據結構來存儲待監聽的文件描述符集合,并通過pool()函數將pollfd集合傳遞給內核,等待內核返回文件描述符的狀態變化。相對于select,poll沒有fd_set集合大小的限制,但并沒有解決輪詢獲取就緒fd的問題,效率也不高。

pollfd結構體的定義

struct pollfd {int fd;         //進行監聽的文件描述符short int events;       //要監聽的事件類型short int revents;      //實際發生的事件類型
};

poll實現網絡通信流程如下圖:

?epoll機制

epoll是linux下最新的I/O多路復用機制,它使用紅黑樹數據結構來存儲待監聽的文件描述符集合,并通過epoll_create、epoll_ctl、epoll_wait等函數實現文件描述符的添加、刪除、監聽操作。相對于select和poll,epoll具有更高的效率和更好的擴展性。

epoll_event 結構體以及 epoll_data 結構體的定義

// 數據結構
// 每一個epoll對象都有一個獨立的eventpoll結構體
// 用于存放通過epoll_ctl方法向epoll對象中添加進來的事件
// epoll_wait檢查是否有事件發生時,只需要檢查eventpoll對象中的rdlist雙鏈表中是否有epitem元素即可
struct eventpoll {/*紅黑樹的根節點,這顆樹中存儲著所有添加到epoll中的需要監控的事件*/struct rb_root  rbr;/*雙鏈表中則存放著將要通過epoll_wait返回給用戶的滿足條件的事件*/struct list_head rdlist;
};

epoll接口

1、int epoll_create(int size);

創建一個epoll的句柄,size用來告訴內核這個監聽的數目一共有多大。epoll 實例內部維護了兩個結構,分別是記錄要監聽的fd和已經就緒的fd,而對于已經就緒的文件描述符來說,它們會被返回給用戶程序進行處理。

2、int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epoll的事件注冊函數,epoll_ctl向 epoll對象中添加、修改或者刪除感興趣的事件,成功返回0,否則返回–1。此時需要根據errno錯誤碼判斷錯誤類型。它不同與select()是在監聽事件時告訴內核要監聽什么類型的事件,而是在這里先注冊要監聽的事件類型。epoll_wait方法返回的事件必然是通過 epoll_ctl添加到 epoll中的。

3、int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
等待事件的產生,類似于select()調用。參數events用來從內核得到事件的集合,maxevents是events集合的大小,且不大于epoll_create()時的size,參數timeout是超時時間(毫秒,0會立即返回,-1將不確定,也有說法說是永久阻塞)。函數返回需要處理的事件數目,返回0表示已超時,返回–1表示錯誤,需要檢查 errno錯誤碼判斷錯誤類型。

epoll 進行網絡通信的流程如下圖:

?

ET模式與LT模式的區別

  • epoll有EPOLLLT和EPOLLET兩種觸發模式,LT是默認的模式,ET是“高速”模式。
  • LT模式下,只要fd還有數據可讀,每次epoll_wait都會返回它的事件,提醒用戶去操作
  • ET模式下,它只會提示一次,直到下次再有數據流入之前都不會再提示了,無論fd中是否還有數據可讀。所以在ET模式下,read它的fd一定要把它的buffer讀完,或者遇到EAGAIN錯誤
  • 因此,在 LT模式下開發基于 epoll的應用要簡單一些,不太容易出錯,而在 ET模式下事件發生時,如果沒有徹底地將緩沖區數據處理完,則會導致緩沖區中的用戶請求得不到響應。

3種機制底層實現的區別

select和poll都是通過輪詢的方式,即內核每次要遍歷監聽的文件描述符集合,判斷每個文件描述符是否有I/O事件發生;

而epoll底層實現是基于事件通知的方式,即當文件描述符狀態發生變化時,內核會向應用程序發起事件通知,這種方式避免了無效的遍歷,從而提高了效率。

在epoll中,使用epoll_wait函數進行事件監聽時,內核將發生的事件文件描述符加入到一個就緒隊列中,等待應用程序處理。如果就緒隊列中沒有任何文件描述符,則epoll_wait函數會阻塞,直到有文件描述符加入就緒隊列,這種方式實現了I/O事件的高效處理和調度。

selectpollepoll
數據結構bitmap數組紅黑樹
最大連接數1024無上限無上限
fd拷貝每次調用select拷貝每次調用poll拷貝fd首次調用epoll_ctl拷貝,每次調用epoll_wait不拷貝
工作效率輪詢:O(n)輪詢:O(n)回調:O(1)

?

參考資料:

https://juejin.cn/post/6844904200141438984

IO多路復用機制詳解 - 知乎

select poll epoll 區別 和 底層實現-掘金

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

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

相關文章

劍指Offer10-I.斐波那契數列 C++

1、題目描述 寫一個函數,輸入 n ,求斐波那契(Fibonacci)數列的第 n 項(即 F(N))。斐波那契數列的定義如下: F(0) 0, F(1) 1 F(N) F(N - 1) F(N - 2), 其中 N > 1. 斐波那契數列由 0 和 …

Redis_事務操作

13. redis事務操作 13.1事務簡介 原子性(Atomicity) 一致性(Consistency) 隔離性(isolation) 持久性(durabiliby) ACID 13.2 Redis事務 提供了multi、exec命令來完成 第一步,客戶端使用multi命令顯式地開啟事務第二步,客戶端把事務中要執行的指令發…

前沿分享-通過經皮神經刺激來治療糖尿病神經性疼痛

經皮神經電刺激(PENS)設備用于對糖尿病周圍神經病變引起的慢性、頑固性疼痛進行多次治療。 放在耳朵上的這種可穿戴設備在幾天內持續提供低水平的脈沖電流。 這是一種安全有效的非麻醉性替代治療慢性疼痛的方法。還有一張設備放在糖足上的照片&#xff0…

向量數據庫 Milvus Cloud Partition Key:租戶數量多,單個租戶數據少的三種解決方案

三種解決方案 這個問題提出的時候,Milvus 的最新版本是 2.2.8,我們做個角色互換,在當時站在這個用戶的角度,留在我們面前的選擇有這么幾個: 為每個租戶創建一個 collection 為每個租戶創建一個 partition 創建一個租戶名稱的標量字段 接下來,我們依次分析下這三種方案的可…

《零基礎實踐深度學習》(第2版)學習筆記,(五)深度學習與計算機視覺

文章目錄 1. 計算機視覺概述2. 圖像分類3. 目標檢測 1. 計算機視覺概述 圖像分類 目標檢測 2. 圖像分類 3. 目標檢測

01-C++數據類型

3、基礎類型 3.1、簡單變量 變量的命名 carDrip和cardRip 或boat_sport和boats_port 此外,還有有前綴的命名,使用前綴表示數據類型。常見的前綴有:str(表示字符串)、n(表示整數值)、b(表示…

深入探究QCheckBox的三種狀態及其用法

文章目錄 引言:三種狀態一、未選中狀態(0):二、選中狀態(2):三、部分選中狀態(1): 判斷方法結論: 引言: QCheckBox是Qt框架中常用的復…

html css實現愛心

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>/* 愛心 */.lo…

修改Linux中SSH的端口

文章目錄 修改Linux中SSH的端口Linux中默認的ssh端口關閉SELinux測試新端口 修改Linux中SSH的端口 Linux中默認的ssh端口 使用root用戶操作 修改前先備份ssh_config cp /etc/ssh/sshd_config /etc/ssh/sshd_config_date "%Y%m%d%H%M%S"修改配置文件&#xff0c;找…

結構體的定義與賦值

1、結構體定義 首先定義一個學生結構體&#xff0c;如下所示&#xff1a; struct Student {int num;char name[32];char sex;int age; }; 接著在主函數中對學生進行聲明&#xff0c;如下所示&#xff1a; #include<iostream> using namespace std;struct Student {in…

2023Robocom省賽(本科組)

RC-u1 亞運獎牌榜 題目鏈接&#xff1a;PTA | 程序設計類實驗輔助教學平臺 (pintia.cn) 題目&#xff1a; 2022 年第 19 屆亞運會即將在杭州召開&#xff0c;杭州已經做好準備歡迎全亞洲的觀眾一同參與亞運盛會了&#xff01; 你正在開發一款跟亞運獎牌計算相關的 App。給定…

“深入探究JVM內部結構與工作原理:解析Java虛擬機“

標題&#xff1a;深入探究JVM內部結構與工作原理 摘要&#xff1a;本文將深入探究Java虛擬機&#xff08;JVM&#xff09;的內部結構與工作原理。我們將介紹JVM的基本組成部分&#xff0c;包括類加載器、運行時數據區和執行引擎。同時&#xff0c;我們將通過一個示例代碼來說明…

直接在html中引入Vue.js的cdn來實現一個簡單的上傳圖片組件

摘要 當使用 Vue.js 的 CDN 來實現一個簡單的上傳圖片組件時&#xff0c;你可以利用 Vue 的數據綁定和事件處理能力&#xff0c;結合 HTML 和 CSS&#xff0c;輕松地創建一個交互式的圖片上傳界面。以下是一個示例&#xff1a; 代碼結構 index.html <!DOCTYPE html> &…

LVS集群和分布式

LVS 一.集群和分布式概念 1.1 集群 在計算機領域&#xff0c;集群早在 1960 年就出現&#xff0c;隨著互聯網和計算機相關技術的發展&#xff0c;現在 集群這一技術已經在各大互聯網公司普及。 1.1.1 集群概念 計算機集群指一組通過計算機網絡連接的計算機&#xff0c;它們…

Rust 重載運算符|復數結構的“加減乘除”四則運算

復數 基本概念 復數定義 由實數部分和虛數部分所組成的數&#xff0c;形如a&#xff0b;bi 。 其中a、b為實數&#xff0c;i 為“虛數單位”&#xff0c;i -1&#xff0c;即虛數單位的平方等于-1。 a、b分別叫做復數a&#xff0b;bi的實部和虛部。 當b0時&#xff0c;a&…

前后端分離------后端創建筆記(06)新增接口頁面布局

本文章轉載于【SpringBootVue】全網最簡單但實用的前后端分離項目實戰筆記 - 前端_大菜007的博客-CSDN博客 僅用于學習和討論&#xff0c;如有侵權請聯系 源碼&#xff1a;https://gitee.com/green_vegetables/x-admin-project.git 素材&#xff1a;https://pan.baidu.com/s/…

Kubernetes入門 四、Pod核心

目錄 什么是PodPod與容器不同Pod如何管理多個容器Pod的管理-工作負載K8s中的資源清單創建使用Pod直接創建Pod使用 Deployment 創建Pod 環境變量重啟策略鏡像拉取策略訪問 DNS 的策略資源限制初始化容器臨時容器&#xff08;了解&#xff09; 什么是Pod Pod 是可以在 Kubernete…

Azure添加網絡接口

添加網絡接口的意義 在 Azure 上&#xff0c;為虛擬機添加網絡接口的意義包括以下幾個方面&#xff1a; 擴展網絡帶寬&#xff1a;通過添加多個網絡接口&#xff0c;可以增加虛擬機的網絡帶寬&#xff0c;提高網絡傳輸速度和數據吞吐量。實現網絡隔離&#xff1a;每個網絡接口…

zabbix-6.4 監控 MySQL

目錄 1、rpm安裝zabbix_agentd服務 2、編寫zabbix_agentd.conf文件 3、編寫模板文件 4、創建mysql用戶并賦權限 5、創建.my.cnf文件 6、將規則添加到SELinux策略中 注意&#xff1a; 若模板無法讀取.my.cnf 信息&#xff0c;從而導致監控報錯&#xff0c;可以嘗試修改模…

虛樹

虛樹是用來優化樹形dp的東西&#xff0c;它的轉移是從一些特殊點&#xff0c;向根節點轉移&#xff0c;期間它有用的轉移點比較特殊。通常詢問次數較多&#xff0c;但特殊點總和較少&#xff0c;就可以每次詢問先建虛樹再跑dp。單調棧建虛樹 O ( k l o g n ) O(klogn) O(klogn)…