前言
我們經常看到阻塞/非阻塞,同步/異步這兩組容易混淆的概念,那么該如何區分呢?
用戶空間和內核空間
內核是操作系統的核心,可以訪問底層硬件設備的所有權限。為了保護內核安全,就把操作系統的內存空間分為:內核空間和用戶空間。
這兩個空間是獨立的。
使用 TCP 發送數據時,需要先將數據從用戶空間拷貝到內核空間,再用內核操作將數據從內核空間發出。
當我們使用 TCP 讀取數據時,先在內核空間准備好,再從內核空間拷貝到用戶空間使用。
IO 五種模型
IO 五種模型分別是 :阻塞型 IO、非阻塞 IO、IO 多路復用、信號驅動 IO、異步 IO。
阻塞型 IO
用戶進程發起請求時,阻塞到數據拷貝到用戶空間才為止。
阻塞 IO 在這兩個階段都是阻塞的。(發送數據拷貝到內核空間是阻塞的,內核空間拷貝到用戶空間,返回數據也是阻塞的)
非阻塞 IO
用戶進程不斷詢問內核,數據准備好了嗎?直到內核說准備好了,將數據從內核空間拷貝到用戶空間。
非阻塞IO第一階段不阻塞(用戶進程詢問內核,會立即得到回應,不阻塞 ),第二階段會阻塞(要等着內核空間拷貝數據到用戶空間並返回)。
IO 多路復用
多個 IO 操作共同使用一個 selector(選擇器)去詢問哪些 IO 需要的數據准備好了,selector 負責通知那些准備好的 IO,那些 IO 再自己去請求內核數據。
IO 多路復用,第一階段會阻塞到 slector 上,第二階段拷貝數據也會阻塞。
信號驅動 IO
用戶進程發起讀取請求前先注冊一個信號給內核說明自己需要什么數據,這個注冊立刻返回。等內核准備好了,主動通知用戶進程,用戶進程再讀取數據,等待數據從內核空間拷貝到用戶空間再返回。
信號驅動 IO,第一階段不阻塞(注冊信號會立刻返回),第二階段阻塞(需要等待數據從內核空間拷貝到用戶空間)。
異步 IO
用戶進程讀取數據請求后立馬返回,當數據從內核空間拷貝到用戶空間再通知用戶直接使用數據。
異步IO,兩個階段都不阻塞。
總結
阻塞和非阻塞
阻塞:調用結果返回之前,當前線程會被掛起,直到調用結果返回。
非阻塞:不能立即得到結果之前,當前線程不會被掛起,可以做其他事。
阻塞調用后必須等着結果返回,非阻塞調用之后愛干什么干什么。
同步與異步
同步:調用者會被阻塞,直到 IO 操作完成,調用的結果隨着請求的結束返回。
異步:調用者不會被阻塞,調用的結果不隨着請求的結束而返回,而是通過通知或者回調函數的形式返回。
也就是說,阻塞/非阻塞,更關心的是當前線程是不是被掛起。而同步/異步,更關心的是調用結果是不是隨着請求結束而返回。
所以 IO 五種模型中,阻塞IO、非阻塞IO、多路復用IO、信號驅動IO都是同步IO,只有最后一個才是異步IO。