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