您現在的位置是:首頁 > 綜合

細節分析Linux中五種IO模型和三種實現方式

  • 由 lee哥的伺服器開發 發表于 綜合
  • 2022-02-04
簡介所以Nginx支援C10K(10K Connections)selectpollepoll操作方式遍歷遍歷回撥底層實現陣列連結串列雜湊表IO效率每次呼叫進行線性遍歷,時間複雜度為O(n)每次呼叫進行線性遍歷,時間複雜度為O(n)事件通知方式

簡述有幾種io控制方式

I/O介紹

作業系統分為兩種I/O

網路IO:本質是socket讀取

磁碟IO:DMA操作讀取

C/C++Linux伺服器開發高階架構學習影片, 內容包括C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,MongoDB,ZK,流媒體,音影片開發,Linux核心,P2P,K8S,Docker,TCP/IP,協程,DPDK多個高階知識點。點選:C/C++Linux伺服器開發/後臺架構師【零聲教育】-學習影片教程-騰訊課堂

每次I/O過程

(DMA)將資料從磁碟檔案先載入至核心記憶體空間(緩衝區),等待資料準備完成,時間較長

(CPU)將資料從核心緩衝區複製到使用者空間的程序的記憶體中,時間較短

I/O模型

同步/非同步:關注的是訊息通訊機制

同步:synchronous,呼叫者等待被呼叫者返回訊息,才能繼續執行

非同步:asynchronous,被呼叫者透過狀態、通知或回撥機制主動通知呼叫者被呼叫者的執行狀態

阻塞/非阻塞:關注呼叫者在等待結果返回之前所處的狀態

阻塞:blocking,指IO操作需要徹底完成後才返回到使用者空間,呼叫結果返回之前,呼叫者被掛起

非阻塞:nonblocking,指IO操作被呼叫後立即返回給使用者一個狀態值,無需等到IO操作徹底完成,最終的呼叫結果返回之前,呼叫者不會被掛起

五種I/O模型:

同步阻塞型、同步非阻塞型、IO多路複用型、訊號驅動I/O型、非同步I/O型

同步阻塞型

細節分析Linux中五種IO模型和三種實現方式

同步阻塞IO模型是最簡單的IO模型,使用者執行緒在核心進行IO操作時被阻塞

使用者執行緒透過系統呼叫read發起IO讀操作,由使用者空間轉到核心空間。核心等到資料包到達後,然後將接收的資料複製到使用者空間,完成read操作

使用者需要等待read將資料讀取到buffer後,才繼續處理接收的資料。整個IO請求的過程中,使用者執行緒是被阻塞的,這導致使用者在發起IO請求時,不能做任何事情,對CPU的資源利用率不夠

同步非阻塞模型

細節分析Linux中五種IO模型和三種實現方式

使用者執行緒發起IO請求時立即返回。但並未讀取到任何資料,使用者執行緒需要不斷地發起IO請求,直到資料到達後,才真正讀取到資料,繼續執行。即“輪詢”機制

整個IO請求的過程中,雖然使用者執行緒每次發起IO請求後可以立即返回,但是為了等到資料,仍需要不斷地輪詢、重複請求,消耗了大量的CPU的資源

是比較浪費CPU的方式,一般很少直接使用這種模型,而是在其他IO模型中使用非阻塞IO這一特性

IO多路複用型

細節分析Linux中五種IO模型和三種實現方式

IO多路複用是指核心一旦發現程序指定的一個或者多個IO條件準備讀取,就通知該程序

多個連線共用一個等待機制,本模型會阻塞程序,但是程序是阻塞在select或者poll這兩個系統呼叫上,而不是阻塞在真正的IO操作上

使用者首先將需要進行IO操作新增到select中,繼續執行做其他的工作(非同步),同時等待select系統呼叫返回。當資料到達時,IO被啟用,select函式返回。使用者執行緒正式發起read請求,讀取資料並繼續執行

從流程上來看,使用select函式進行IO請求和同步阻塞模型沒有太大的區別,甚至還多了新增監視IO,以及呼叫select函式的額外操作,效率更差。並且阻塞了兩次,但是第一次阻塞在select上時,select可以監控多個IO上是否已有IO操作準備就緒,即可達到在同一個執行緒內同時處理多個IO請求的目的。而不像阻塞IO那種,一次只能監控一個IO

雖然上述方式允許單執行緒內處理多個IO請求,但是每個IO請求的過程還是阻塞的(在select函式上阻塞),平均時間甚至比同步阻塞IO模型還要長。如果使用者執行緒只是註冊自己需要的IO請求,然後去做自己的事情,等到資料到來時再進行處理,則可以提高CPU的利用率

IO多路複用是最常使用的IO模型,但是其非同步程度還不夠“徹底”,因它使用了會阻塞執行緒的select系統呼叫。因此IO多路複用只能稱為非同步阻塞IO模型,而非真正的非同步IO

在校生,轉行linux平臺開發人員,Linux基礎知識點學習資料點選 正在跳轉 獲取

細節分析Linux中五種IO模型和三種實現方式

在職人員學習提升,有一定基礎的轉行人員,Linux後臺伺服器開發高階進階知識點學習資料點選 「連結」 獲取

細節分析Linux中五種IO模型和三種實現方式

訊號驅動I/O型

細節分析Linux中五種IO模型和三種實現方式

訊號驅動IO:signal-driven I/O

使用者程序可以透過sigaction系統呼叫註冊一個訊號處理程式,然後主程式可以繼續向下執行,當有IO操作準備就緒時,由核心通知觸發一個SIGIO訊號處理程式執行,然後將使用者程序所需要的資料從核心空間複製到使用者空間

此模型的優勢在於等待資料報到達期間程序不被阻塞。使用者主程式可以繼續執行,只要等待來自訊號處理函式的通知

該模型並不常用

非同步I/O型

細節分析Linux中五種IO模型和三種實現方式

非同步IO與訊號驅動IO最主要的區別是訊號驅動IO是由核心通知何時可以進行IO操作,而非同步IO則是由核心告訴使用者執行緒IO操作何時完成。訊號驅動IO當核心通知觸發訊號處理程式時,訊號處理程式還需要阻塞在從核心空間緩衝區複製資料到使用者空間緩衝區這個階段,而非同步IO直接是在第二個階段完成後,核心直接通知使用者執行緒可以進行後續操作了

相比於IO多路複用模型,非同步IO並不十分常用,不少高效能併發服務程式使用IO多路複用模型+多執行緒任務處理的架構基本可以滿足需求。目前作業系統對非同步IO的支援並非特別完善,更多的是採用IO多路複用模型模擬非同步IO的方式(IO事件觸發時不直接通知使用者執行緒,而是將資料讀寫完畢後放到使用者指定的緩衝區中)

五種I/O模型

常用的是IO多路複用型,比如Nginx

細節分析Linux中五種IO模型和三種實現方式

實現I/O模型的方式

Select:Linux實現對應,I/O複用模型,BSD4。2最早實現,POSIX標準,一般作業系統均有實現

Poll:Linux實現,對應I/O複用模型,System V unix最早實現

Epoll:Linux特有,對應I/O複用模型,具有訊號驅動I/O模型的某些特性

Kqueue:FreeBSD實現,對應I/O複用模型,具有訊號驅動I/O模型某些特性

/dev/poll:SUN的Solaris實現,對應I/O複用模型,具有訊號驅動I/O模型的某些特性

Iocp Windows實現,對應第5種(非同步I/O)模型

Apache使用的是Select,Nginx使用的是Epoll。所以Nginx支援C10K(10K Connections)

\

select

poll

epoll

操作方式

遍歷

遍歷

回撥

底層實現

陣列

連結串列

雜湊表

IO效率

每次呼叫進行線性遍歷,時間複雜度為O(n)

每次呼叫進行線性遍歷,時間複雜度為O(n)

事件通知方式,每當fd就緒,系統註冊的回撥函式就會被呼叫,將就緒fd放到dllis裡面,時間複雜度O(1)

最大連線數

1024(x86)或2048(x64)

無上限

無上限

fd複製

每次呼叫select,都需要把fd集合從使用者態複製到核心態

每次呼叫poll,都需要把fd集合從使用者態複製到核心態

呼叫epoll_ctl時複製進核心並儲存,之後每次epoll_wait不復制

細節分析Linux中五種IO模型和三種實現方式

Select

POSIX所規定,目前幾乎在所有的平臺上支援,其良好跨平臺支援也是它的一個優點,本質上是透過設定或者檢查存放fd標誌位的資料結構來進行下一步處理

缺點:

單個程序能夠監視的檔案描述符的數量存在最大限制,在Linux上一般為1024(多年生產環境得到的最佳值),可以透過修改宏定義FD_SETSIZE,再重新編譯核心實現,但是這樣也會造成效率的降低

單個程序可監視的fd數量被限制,預設是1024,修改此值需要重新編譯核心

對socket是線性掃描,即採用輪詢的方法,效率較低

select 採取了記憶體複製方法來實現核心將 FD 訊息通知給使用者空間,這樣一個用來存放大量fd的資料結構,這樣會使得使用者空間和核心空間在傳遞該結構時複製開銷大

Poll

本質上和select沒有區別,它將使用者傳入的陣列複製到核心空間,然後查詢每個fd對應的裝置狀態

其沒有最大連線數的限制,原因是它是基於連結串列來儲存的

大量的fd的陣列被整體複製於使用者態和核心地址空間之間,而不管這樣的複製是不是有意義

poll特點是“水平觸發”,如果報告了fd後,沒有被處理,那麼下次poll時會再次報告該fd

邊緣觸發:只通知一次

Epoll

在Linux 2。6核心中提出的select和poll的增強版本

支援水平觸發LT和邊緣觸發ET,最大的特點在於邊緣觸發,它只告訴程序哪些fd剛剛變為就需態,並且只會通知一次

使用“事件”的就緒通知方式,透過epoll_ctl註冊fd,一旦該fd就緒,核心就會採用類似callback的回撥機制來啟用該fd,epoll_wait便可以收到通知

優點:

沒有最大併發連線的限制:能開啟的FD的上限遠大於1024(1G的記憶體能監聽約10萬個埠),具體檢視/proc/sys/fs/file-max,此值和系統記憶體大小相關

效率提升:非輪詢的方式,不會隨著FD數目的增加而效率下降;只有活躍可用的FD才會呼叫callback函式,即epoll最大的優點就在於它只管理“活躍”的連線,而跟連線總數無關

記憶體複製,利用mmap(Memory Mapping)加速與核心空間的訊息傳遞;即epoll使用mmap減少複製開銷

Top