IO - 同步,異步,阻塞,非阻塞

五種IO Model一直不太清楚,今天看了大神寫的文章,有種豁然開朗的感覺。

但是感覺大神文章中寫的例子不太詳細(xì),所以自己又寫了一個例子來說明這幾種模型的區(qū)別。

建議配合大神的文章看。

假設(shè)你(進(jìn)程)是旅游團(tuán)負(fù)責(zé)人,需要去辦事處(kernel)為旅游團(tuán)的人辦理十個簽證。

辦理每個簽證時,柜員都需要做兩件事(對應(yīng)read操作的兩個階段):

  1. 查找簽證人員的相關(guān)數(shù)據(jù)(等待數(shù)據(jù)準(zhǔn)備)。
  2. 處理這些數(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é)底,還是需要同步模型。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容