您好,登錄后才能下訂單哦!
本篇內容介紹了“IO的五種模型是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
我們經常提到 IO、NIO 這些名詞。那么,到底什么是 IO 呢?什么又是 NIO 呢?
另外,我們平時又會聽到兩組很相似的概念:阻塞 / 非阻塞、同步 / 異步。那么,阻塞和非阻塞有什么區別呢?同步和異步又有什么區別呢?很多同學對這兩組概念都比較容易混淆,也講不清楚。
所以,本期教程就從網絡 IO 的角度出發并用生活中常見的案例來白話 IO 的五種模型,以及上面兩組概念。
用戶空間和內核空間
操作系統的核心是內核,它獨立于普通的應用程序,可以訪問受保護的內核空間,也有訪問底層硬件設備的所有權限。為了保護內核的安全,現在操作系統一般都強制用戶進程不能直接操作內核,所以操作系統把內存空間劃分成了兩個部分:內核空間和用戶空間。
這就好比,飯店老板把整個飯店劃分成兩個部分:大廳和廚房。大廳用于顧客吃飯,廚房用于廚師做飯,廚房的門上面一般還會寫著:“廚房重地,閑人免進”,也就是顧客一般不具有直接使用廚房的特性。
所以,當我們使用 TCP 發送數據的時候,需要先將數據從用戶空間拷貝到內核空間,再由內核操作將數據從內核空間發送出去;當我們使用 TCP 讀取數據的時候,數據先在內核空間準備好,再從內核空間拷貝到用戶空間供用戶進程使用。
這就好比,當我們在飯店吃飯的時候,先在客廳點好菜,再由服務員把我們的菜單傳遞進廚房;當廚房做好了菜,再從廚房由服務員傳遞到客廳一樣。
所以,一次 IO 的讀取操作分為兩個階段(寫入操作類似):
等待內核空間數據準備階段
數據從內核空間拷貝到用戶空間
為此,Unix 根據這兩個階段又把 IO 分成了以下五種 IO 模型:
阻塞型 IO
非阻塞型 IO
IO 多路復用
信號驅動 IO
異步 IO
下面我們一一道來。
阻塞型 IO
阻塞型 IO,即當用戶進程發起請求時,一直阻塞直到數據拷貝到用戶空間為止才返回。
阻塞型 IO 在兩個階段是連續阻塞著的,直到數據返回。
這就好比,你去路邊買快餐,這家店比較低級,只有一輛車一個老板。點完餐后,你傻傻地看著老板開始打菜,然后拿給你。整個過程中,你只能看著老板打完菜并拿給你,這兩個階段你都是阻塞的。
非阻塞型 IO
非阻塞型 IO,用戶進程不斷詢問內核,數據準備好了嗎?一直重試,直到內核說數據準備好了,然后把數據從內核空間拷貝到用戶空間,返回成功,開始處理數據。
非阻塞型 IO 第一階段不阻塞,第二階段阻塞。
這就好比,你去小炒店,這家店高級一點,有獨立的店面。點完餐后,你可以邊玩手機邊等。隔了一會你跑過去問一下老板 “我的菜好了沒”,老板說 “還沒好”;隔一會你又跑過去問了下 “我的菜好了沒”,老板說 “還沒有”;幾次后,你又說 “老板,我的菜好了沒”,老板說 “來了來了”,然后你看著他把菜端到你面前。整個過程中,詢問 “菜好了沒” 你不用阻塞,老板立即回應你,你可以立即玩手機,但是端菜的時候你是傻傻地看著他端的,這期間你無法玩手機,你是阻塞的。
IO 多路復用
IO 多路復用,多個 IO 操作共同使用一個 selector(選擇器)去詢問哪些 IO 準備好了,selector 負責通知那些數據準備好了的 IO,它們再自己去請求內核數據。
IO 多路復用,第一階段會阻塞在 selector 上,第二階段拷貝數據也會阻塞。
這就好比,你去川菜館吃飯,這家飯店比較大,人也多,還有個漂亮的服務員。你點完菜后,勾搭了一下服務員 “美女,我點個辣子雞丁,好了通知我一下哦”,美女也沒搭理你。其它人也是這么勾搭美女的。然后,美女忙得不可開交,隔一會去廚房看一下,哪些菜好了,每次出來,都會喊 “那誰誰誰,你的啥啥菜好了,自己過來端一下。”。整個過程中,美女去廚房看菜是阻塞的,因為沒有菜好的時候她還要等一會;你跑過去端菜也是阻塞的。一部分阻塞在美女身上,一部分阻塞在你身上。
信號驅動 IO
信號驅動 IO,用戶進程發起讀取請求之前先注冊一個信號給內核說明自己需要什么數據,這個注冊請求立即返回,等內核數據準備好了,主動通知用戶進程,用戶進程再去請求讀取數據,此時,需要等待數據從內核空間拷貝到用戶空間再返回。
信號驅動,第一階段不阻塞,第二階段阻塞。
這就好比,你去 “金拱門” 吃麥當勞一樣。你在旁邊的機器上點完餐后出來一張小票 “1024 號”,然后你邊玩手機邊等。過了一會,喇叭喊,“1024 號,請取餐。1024 號,請取餐。”,然后,你屁顛屁顛地跑過去取餐。整個過程中,點餐是立即返回的,之后想干啥干啥,不阻塞(也就是說你不用傻等著餐做好);取餐的過程你需要從柜臺端到你的位置上,是阻塞的。
異步 IO
異步 IO,用戶進程發起讀取請求后立馬返回,當數據完全拷貝到用戶空間后通知用戶直接使用數據。
異步 IO,兩個階段都不阻塞。
這就好比,你去吃 “漁粉”。掃碼點餐后,你完全不用管,過了一會,一個大媽把飯菜端到你面前,還貼心地說了句 “客官,請慢用”,然后你幸福地吃下了這碗 “金湯漁粉”。整個過程中,你既不用傻等著漁粉做好,也不用看著大媽把菜端到你面前或者你自己去端,完全不阻塞,純異步。所以,這種體驗是最好的。
所以,如果把吃飯的過程分成兩個部分:“準備飯菜” 和 “端菜”,那么:
如果你傻等著兩個階段完成,就是阻塞 IO;
如果你隔一會詢問一下 “菜做好了沒”,期間你可以玩手機,但是端菜的時候你傻傻地看著老板端過來,就是非阻塞 IO;
如果你和其他人都委托服務員幫你們隔一會看一下 “菜做好了沒”,但是端菜需要自己去端,就是 IO 多路復用;
如果是機器點餐,機器喊話取餐,就是信號驅動 IO;
如果是掃碼點餐,自動上餐,就是異步 IO;
阻塞與非阻塞
阻塞,是指調用結果返回之前,當前線程會被掛起,直到調用結果返回。比如,你傻等著端菜結束,你就是阻塞的。
非阻塞,是指不能立即得到結果之前,當前線程不被掛起,而是可以繼續做其它的事。比如,你邊玩手機邊等飯菜準備好,你就是非阻塞的。
簡單點,就是阻塞調用你必須掛起傻等著結果返回,非阻塞調用你不關心結果,調用之后你愛干嘛干嘛。
同步與異步
關于同步與異步,我們直接看看 POSIX 中的定義:
A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes;
An asynchronous I/O operation does not cause the requesting process to be blocked;
同步,調用者會被阻塞直到 IO 操作完成,調用的結果隨著請求的結束而返回。
異步,調用者不會被阻塞,調用的結果不隨著請求的結束而返回,而是通過通知或回調函數的形式返回。
阻塞 / 非阻塞,更關心的是當前線程是不是被掛起。
同步 / 異步,更關心的是調用結果是不是隨著請求結束而返回。
這里的阻塞是指整個 IO 過程中是否有阻塞,更確切地說是 recvfrom 這個系統調用是否會阻塞,在我們的案例中,可以理解為 “端菜” 這個行為對于你來說是不是阻塞的。
所以,阻塞型 IO、非阻塞型、IO 多路復用、信號驅動 IO 都是同步 IO,只有最后一種才是異步 IO。
為什么不選擇異步 IO?
通過上面的分析,異步 IO 才是最牛的 IO 模型,那么,我們為什么不選擇異步 IO 呢?
那是因為異步 IO 在 linux 上還不成熟,而我們的服務器通常都是 linux,所以現在大部分框架都不是很支持異步 IO,包括 Netty 之前實現了一版,但是后面給廢棄掉了。
“IO的五種模型是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。