五種IO Model一直不太清楚,今天看了大神寫的文章,有種豁然開朗的感覺。
但是感覺大神文章中寫的例子不太詳細(xì),所以自己又寫了一個例子來說明這幾種模型的區(qū)別。
建議配合大神的文章看。
假設(shè)你(進(jìn)程)是旅游團(tuán)負(fù)責(zé)人,需要去辦事處(kernel)為旅游團(tuán)的人辦理十個簽證。
辦理每個簽證時,柜員都需要做兩件事(對應(yīng)read操作的兩個階段):
- 查找簽證人員的相關(guān)數(shù)據(jù)(等待數(shù)據(jù)準(zhǔn)備)。
- 處理這些數(shù)據(jù)辦理簽證(將數(shù)據(jù)從內(nèi)核拷貝到進(jìn)程中)。
辦理簽證整個過程代表進(jìn)程向kernel請求數(shù)據(jù)的過程。
文章中的“等待”均表示進(jìn)程阻塞。
blocking IO 模型
你找到一名柜員,一個簽證一個簽證按順序地辦。整個過程你都在柜員面前等待。直到業(yè)務(wù)辦完。
non-blocking IO 模型
你找到一名柜員辦理簽證,她立刻告知你,相關(guān)數(shù)據(jù)還沒準(zhǔn)備好。
于是你去到另一名柜員面前,辦理另一個簽證。直到你找了10個柜員辦理這十個簽證。
然后你回到第一名柜員面前,問她數(shù)據(jù)準(zhǔn)備好沒有。被告知沒有的話,你又去下一名柜員面前問同樣的問題。直到某名柜員回復(fù)說,數(shù)據(jù)已經(jīng)準(zhǔn)備好了,于是你在她面前等待她處理你的數(shù)據(jù)。直到她處理完數(shù)據(jù)辦理好簽證,你再繼續(xù)去下一名柜員面前詢問。
評價
非阻塞指的是:在你請求辦理業(yè)務(wù)的時候,柜員會立即告知你結(jié)果--相關(guān)數(shù)據(jù)還沒準(zhǔn)備好 或者 數(shù)據(jù)已經(jīng)準(zhǔn)備好了。
但是需要特別注意的是,非阻塞和non-blocking IO 模型是不等同的。
non-blocking IO 模型里面也包含了阻塞的。在柜員處理數(shù)據(jù)的時候你是需要在她面前等待的。
IO multiplexing 模型
在第二種模型下,你每次詢問柜員準(zhǔn)備好數(shù)據(jù)沒有,都需要浪費(fèi)柜員一定的時間。詢問太多次,辦事處的效率大大地降低了。于是辦事處開發(fā)了一種機(jī)器。
當(dāng)你使用這種機(jī)器時,它可以替你叫柜員辦理簽證,并且替你詢問柜員數(shù)據(jù)準(zhǔn)備好沒有(這個機(jī)器也是通過輪詢的方式詢問,只是它詢問的速度比較快)。你需要做的就是在這個機(jī)器面前等待,不能做其他事情。
當(dāng)它顯示某名柜員已經(jīng)準(zhǔn)備好數(shù)據(jù)時,你就去到那名柜員面前等待她辦理簽證。辦理好簽證之后你再來機(jī)器面前等待。直到全部業(yè)務(wù)辦理完。
評價
在這個過程中,你要么在機(jī)器面前等待,要么去到柜員面前等待
該模型相對第二個模型的好處在于,提高了詢問柜員的效率。
但是如果你需要辦理的簽證很少,那么辦事處生產(chǎn)機(jī)器的成本就劃不來了。這個時候可能其他模型會是更好的選擇。
Asynchronous I/O 模型
你有個小弟,你打電話讓你小弟去辦事處辦理簽證,讓他辦理好之后再打電話通知你。
然后你就去處理其它無關(guān)的事情了(回家做飯什么的。。)
假設(shè)小弟一直沒有回復(fù)你電話,那你可能就把簽證這件事情完全忘記了。
甚至你也不記得自己是旅行團(tuán)的負(fù)責(zé)人了,而是一直在家里愉快地做飯。。
評價
個人認(rèn)為,Asynchronous I/O 模型和其他幾項(xiàng)最主要的區(qū)別在于:異步不會等待回應(yīng),就立刻進(jìn)行自己的其他事情。而同步則不一樣,進(jìn)程會等到有結(jié)果返回了再考慮下一步動作。
異步和非阻塞并不等同,甚至兩個概念完全沒有關(guān)系:
異步的情況下,進(jìn)程請求后,不會理會是否有結(jié)果返回。然后就去做其他事情了。
//異步
var a = requireData(function(data){
//do something with data
})
// a is pointless
// do something without data
而在非阻塞的情況下,進(jìn)程請求后,是可以立刻得到一個結(jié)果的。進(jìn)程可以基于這個結(jié)果去做其他事情。
下面的代碼可以看出,非阻塞的寫法其實(shí)和同步的寫法一樣。
// 非阻塞
var a = requireData()
if (isError(a)) {
// keep require data
var a = requireData()
} else {
// do something with data
}
如果非阻塞情況下,想要實(shí)現(xiàn)異步中的效果,則需要引入一個setTimeout才可以。而我們都知道,setTimeout其實(shí)是一個異步函數(shù)。
那么可不可以理解為,setTimeout其實(shí)就是Asynchronous I/O 模型中的旅行團(tuán)負(fù)責(zé)人,而這時候,非阻塞請求成為了小弟呢?∑( ̄□ ̄;)雖然這種比喻并不恰當(dāng)。
// 非阻塞情況下,實(shí)現(xiàn)異步中的效果
var keepRequire = function () {
setTimeout(function() {
var data = requireData();
if (isError(data)) {
keepRequire()
} else {
// do something with data
}
}, 100);
}
keepRequire()
// do something without data
總結(jié)
阻塞和非阻塞的區(qū)別在于:
阻塞不能立刻返回結(jié)果,然后它還讓你(進(jìn)程)干耗著,直到有結(jié)果返回了
非阻塞會立刻返回結(jié)果,這樣你就不用干耗著了。(當(dāng)然這個結(jié)果很可能是error)
而同步和異步的區(qū)別在于:
同步是有結(jié)果了,才進(jìn)行下一步計(jì)劃。
異步則是不等有沒有結(jié)果,先做了其他事情再說。
阻塞非阻塞和同步異步的概念不具備可比性,但本人認(rèn)為,阻塞和非阻塞應(yīng)該算是屬于同步的。
因?yàn)橥绞切枰却Y(jié)果才進(jìn)行下一步計(jì)劃,這時候阻塞(不能立刻返回結(jié)果),非阻塞(立刻返回結(jié)果)的概念對同步而言就很重要了。
但是異步根本不需要等待結(jié)果啊,它才懶得管你阻不阻塞呢,就是這么傲嬌(°ω°?)*
由于異步的不確定性太強(qiáng)了(即使在請求信息的時候出錯了(小弟掛了),也不會有出錯信息),所以現(xiàn)在主流的應(yīng)該是用第三種模式。
另外,我覺得有必要注意的是:在Asynchronous I/O 模型,你通知了你小弟去辦事。那么你小弟很可能就是用前面三種模型的其中之一去辦事的。所以歸根結(jié)底,還是需要同步模型。。