linux 的 5 種 IO 模型
一、這裏 IO 是什麼
操作系統爲了保護自己,設計了用戶態、內核態兩個狀態。應用程序一般工作在用戶態,當調用一些底層操作的時候(比如 IO 操作),就需要切換到內核態纔可以進行
服務器從網絡接收的大致流程如下:
1、數據通過計算機網絡來到了網卡
2、把網卡的數據讀取到 socket 緩衝區
3、把 socket 緩衝區讀取到用戶緩衝區,之後應用程序就可以使用
核心就是兩次讀取操作,五大 IO 模型的不同之處也就在於這兩個讀取操作怎麼交互
二、同步 / 異步和阻塞 / 非阻塞
-
同步 / 異步:這個是應用層面的概念,指的是調用一個函數,我們是等這個函數執行完再繼續執行下一步,還是調完函數就繼續執行下一步,另起一個線程去執行所調用的函數。關注的是線程間的協作。同步和異步關注的是消息通信機制。所謂同步,就是在發出一個調用時,自己需要參與等待結果的過程, 則爲同步, 前面四個 IO 都自己參與了, 所以也稱爲同步 IO. 異步 IO, 則指出發出調用以後, 到數據準備完成, 自己都未參與, 則爲異步.
-
阻塞 / 非阻塞:這個是硬件層面的概念,阻塞是指 cpu “被”休息,處理其他進程去了,比如 IO 操作,而非阻塞則是 cpu 仍然會執行,不會切換到其他進程。關注的是 CPU 會不會 “被” 休息,表現在應用層面就是線程會不會 “被” 掛起
三、五種 io 模型
- 阻塞 io
應用調用 recvfrom 讀取數據時,其系統調用直到數據包到達且被複制到應用緩衝區中或者發送錯誤時才返回,在此期間一直會等待,進程從調用到返回這段時間內都是被阻塞的稱爲阻塞 IO。在內核將數據準備好之前, 系統調用會一直等待. 所有的套接字, 默認都是阻塞方式
-
應用進程向內核發起 recfrom 讀取數據
-
內核進行準備數據報(此時應用進程阻塞)
-
內核將數據從內核負複製到應用空間。
-
複製完成後,返回成功提示
- 非阻塞 io
當應用發起讀取數據申請時,如果內核數據沒有準備好會即刻告訴應用 B,不會讓 B 在這裏等待, 如果內核還未將數據準備好, 系統調用仍然會直接返回, 並且返回 EWOULDBLOCK 錯誤碼。非阻塞 IO 往往需要程序員循環的方式反覆嘗試讀寫文件描述符
-
應用進程向內核發起 recvfrom 讀取數據。
-
內核數據報沒有準備好,即刻返回 EWOULDBLOCK 錯誤碼。
-
應用進程再次向內核發起 recvfrom 讀取數據。
-
內核倘若已有數據包準備好就進行下一步驟,否則還是返回錯誤碼
-
內核將數據拷貝到用戶空間。
-
完成後,返回成功提示
3.io 多路複用
由一個線程監控多個網絡請求(fd 文件描述符,linux 系統把所有網絡請求以一個 fd 來標識), 來完成數據狀態詢問的操作,當有數據準備就緒之後再分配對應的線程去讀取數據
-
應用進程向內核發起 recvfrom 讀取數據
-
內核進行準備數據報(此時應用進程阻塞)
-
內核倘若已有數據包準備好則通知應用線程
-
內核將數據拷貝到用戶空間
-
完成後,返回成功提示
下面給出一個應用系統和內核之間的流程圖
- 信號驅動
信號驅動 IO 是在調用 sigaction 時候建立一個 SIGIO 的信號聯繫,當內核準備好數據之後再通過 SIGIO 信號通知線程, 此 fd 準備就緒,當線程收到可讀信號後,此時再向內核發起 recvfrom 讀取數據的請求,因爲信號驅動 IO 的模型下, 應用線程在發出信號監控後即可返回,不會阻塞,所以一個應用線程也可以同時監控多個 fd
-
應用進程向內核發起 recvfrom 讀取數據
-
內核進行準備數據報,即刻返回
-
內核倘若已有數據包準備好則通知應用線程
-
應用進程向內核發起 recvfrom 讀取數據
-
內核將數據拷貝到用戶空間
-
完成後,返回成功提示
下面給出一個應用系統和內核之間的流程圖
- 異步 IO
應用只需要向內核發送一個讀取請求, 告訴內核它要讀取數據後即刻返回;內核收到請求後會建立一個信號聯繫,當數據準備就緒,內核會主動把數據從內核複製到用戶空間,等所有操作都完成之後,內核會發起一個通知告訴應用
-
應用進程向內核發起 recvfrom 讀取數據
-
內核進行準備數據報,即刻返回
-
內核收到後會建立一個信號聯繫,倘若已有數據包準備好,內核將數據拷貝到用戶空間
-
完成後,返回成功提示
四、五種 io 對比
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/-_xQVtG7dPJCUCCMijp_HA