一文徹底搞定(阻塞/非阻塞/同步/非同步)網路IO、併發程式設計模型、非同步程式設計模型的愛恨情仇

arvin-hermit發表於2021-11-01

是否和我有一樣的困惑。什麼阻塞IO、非阻塞IO、同步IO、非同步IO,多路複用(epoll)等本質還是同步IO,這時可能你和我一樣懵逼多路複用是同步的IO,那麼使用epoll的nginx、redis、swoole等服務端程式又是非同步的,這不前後矛盾麼?網上文章又是五花八門,越看越糊塗。終於我無法忍受這樣概念不清晰,亂麻一般的縈繞在我的心頭。我決定要徹底撥開雲霧見藍天,啊!終於在一個陽光明媚的午後,就徹底頓悟了,這感覺如同德芙一般絲滑。今天就跟隨我的步伐讓你有絲滑一般的感覺,兄弟們走起來!!!!

IO:IO是input/ouput英文縮寫,顧名思義就是輸入輸出的意思,在計算中以CPU為視角,所有和外設(鍵盤、顯示卡、網路卡、印表機的等)的資料操作都是涉及IO操作,外設流向CPU的是input,流向外設的就是ouput。網路IO就是網路卡和CPU之間的資料互動。

思考一個問題:網路卡資料流向CPU都經過哪些流程

一文徹底搞定(阻塞/非阻塞/同步/非同步)網路IO、併發程式設計模型

資料流向示意圖

使用者程式發起一個網路IO操作的時候,大致上分為三個部分

  1. 使用者程式讀取資料,讀取資料只會有三個可能(有資料、沒有資料、出錯)
  2. 網路卡資料從網路卡外設到核心空間(此過程現代計算機是不需要CPU參與,網路卡控制器通過DMA技術直接搬運到核心空間)。資料完成空網路卡控制器會發出中斷訊號。
  3. 資料到核心之後CPU負責複製(在此我們先不考慮零拷貝情況)到使用者空間。

使用者程式和核心互動圍繞著1和3進行。到此在1和3環節就會有很多故事發生了。且聽我慢慢道來!!!!

在給出分類之前我先丟擲阻塞、非阻塞、非同步、同步的定義,定義來自《UNIX 網路程式設計卷一 》的 6.2 章節
根據 POSIX 定義:

  • A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes(導致請求程式阻塞, 直到 IO 操作完成)。
  • An asynchronous I/O operation does not cause the requesting process to be blocked(不導致請求程式阻塞)。

上述定義是說:如果在1階段系統掛起使用者程式,那麼該IO操作就是阻塞IO,反之不掛起,就是非阻塞IO。如果在2階段系統掛起使用者程式,那麼這次IO操作就是同步,反之不掛起就是非同步。

有了上述的定義,我們如何尚方寶劍一樣,在也不擔心傻傻分不清網路IO相關晦澀難懂的概念了。就如同初中老師教會我們如何判斷什麼是化學反應變化是物理變化,判斷標準就是看有無新的物質生成。我們判斷網路分類標準就是如上述的定義。對,就是這麼狹義!!!

操作針對上述1和3處理行為,我們將網路IO分類下列5類。

  • 阻塞IO 此IO操作在1和3兩個階段,使用者程式都在休眠狀態
  • 非阻塞I/O 此IO操作在1階段未被掛起,3階段被掛起
  • 多路複用I/O 此IO操作在1階段 (select,poll)被掛起、epoll未掛起,3階段被掛起
  • 訊號驅動I/O 此IO操作在1階段未掛起,的資料到從網路卡到核心之後,CPU通過訊號機制通知使用者程式。使用者程式3階段被掛起
  • 非同步I/O 此IO操作在1和3階段都不需要使用者程式參與,資料拷貝完成後CPU會通知使用者程式

此刻來一張很經典的圖

一文徹底搞定(阻塞/非阻塞/同步/非同步)網路IO、併發程式設計模型

IO對比圖

從圖中和上述定義就能看到真正的非同步IO只有最後一個是。其餘四個都是同步IO。對於同步和非同步深入理解,其實在3這個階段CPU需要拷貝資料到使用者空間,等於使用者程式切換到核心空間去執行拷貝操作,這個時候使用者程式只能被掛起等待CPU拷貝資料直到完成。使用者程式被掛起這段時間,使用者程式的後續程式碼都是無法執行的只能同步等待。

追求效能極致的程式設計師們,不遺餘力地壓榨CPU。基於系統提供的網路IO模型,人類設計出形形色色的併發模型。

  • 阻塞IO這種是完美無法提供併發的能力,只能序列的去處理客戶端連線,所以網路IO就有了新的發展,進入到了非阻塞IO
  • 非阻塞IO 這種IO模型 就能設計出多執行緒、多程式併發模型
  • 多路複用 這便是併發能力祕密武器,基於這種網路IO 衍生出了 reactor反應堆併發模型,大名鼎鼎的nginx、redis就是reactor模型
  • 訊號驅動和非同步IO 暫時還未有更多的使用

在上述的併發模型中其實單純靠多程式和多執行緒,還無法達到人們的預期。所以就有了非同步程式設計模型,非同步程式設計模型的宗旨就是,使用者程式呼叫同步的網路IO 模擬非同步IO。人們經常說的非同步IO更多指的是 非同步程式設計模型(netty就是典型的非同步IO)

在非同步程式設計過有兩個核心的技術技術回撥和協程。

並非同步IO就會效能差,非同步IO就會效能好。要具體情況而定!!!

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章