1. Unix五種IO模型與Java IO模型演進(jìn)

轉(zhuǎn)自 http://www.tianshouzhi.com/api/tutorials/netty/221

同步異步阻塞非阻塞概念

  1. 同步與異步同步和異步關(guān)注的是消息通信機(jī)制 (synchronous communication/ asynchronous communication)所謂同步扇售,就是在發(fā)出一個(gè)調(diào)用時(shí)被因,在沒有得到結(jié)果之前溺职,該調(diào)用就不返回术健。但是一旦調(diào)用返回熟菲,就得到返回值了府瞄。換句話說钉答,就是由調(diào)用者主動(dòng)等待這個(gè)調(diào)用的結(jié)果例获。而異步則是相反,調(diào)用在發(fā)出之后印叁,這個(gè)調(diào)用就直接返回了被冒,所以沒有返回結(jié)果。換句話說轮蜕,當(dāng)一個(gè)異步過程調(diào)用發(fā)出后昨悼,調(diào)用者不會(huì)立刻得到結(jié)果。而是在調(diào)用發(fā)出后跃洛,被調(diào)用者通過狀態(tài)率触、通知來通知調(diào)用者,或通過回調(diào)函數(shù)處理這個(gè)調(diào)用汇竭。典型的異步編程模型比如Node.js舉個(gè)通俗的例子:你打電話問書店老板有沒有《分布式系統(tǒng)》這本書葱蝗,如果是同步通信機(jī)制,書店老板會(huì)說细燎,你稍等两曼,”我查一下",然后開始查啊查玻驻,等查好了(可能是5秒悼凑,也可能是一天)告訴你結(jié)果(返回結(jié)果)。而異步通信機(jī)制击狮,書店老板直接告訴你我查一下啊佛析,查好了打電話給你,然后直接掛電話了(不返回結(jié)果)彪蓬。然后查好了寸莫,他會(huì)主動(dòng)打電話給你。在這里老板通過“回電”這種方式來回調(diào)档冬。
  2. 阻塞與非阻塞阻塞和非阻塞關(guān)注的是程序在等待調(diào)用結(jié)果(消息膘茎,返回值)時(shí)的狀態(tài).阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當(dāng)前線程會(huì)被掛起酷誓。調(diào)用線程只有在得到結(jié)果之后才會(huì)返回披坏。非阻塞調(diào)用指在不能立刻得到結(jié)果之前,該調(diào)用不會(huì)阻塞當(dāng)前線程盐数。還是上面的例子棒拂,你打電話問書店老板有沒有《分布式系統(tǒng)》這本書,你如果是阻塞式調(diào)用,你會(huì)一直把自己“掛起”帚屉,直到得到這本書有沒有的結(jié)果谜诫,如果是非阻塞式調(diào)用,你不管老板有沒有告訴你攻旦,你自己先一邊去玩了喻旷, 當(dāng)然你也要偶爾過幾分鐘check一下老板有沒有返回結(jié)果。在這里阻塞與非阻塞與是否同步異步無關(guān)牢屋。跟老板通過什么方式回答你結(jié)果無關(guān)且预。

IO 是主存和外部設(shè)備 ( 硬盤、終端和網(wǎng)絡(luò)等 ) 拷貝數(shù)據(jù)的過程烙无。 IO 是操作系統(tǒng)的底層功能實(shí)現(xiàn)锋谐,底層通過 I/O 指令進(jìn)行完成。在本教程中皱炉,我們所說的IO指的都是網(wǎng)絡(luò)IO怀估。

《UNIX網(wǎng)絡(luò)編程:卷一》第六章——I/O復(fù)用。書中向我們提及了5種類UNIX下可用的I/O模型:

1合搅、阻塞式I/O:blocking IO

2、非阻塞式I/O: nonblocking IO

3歧蕉、I/O復(fù)用(select灾部,poll,epoll...):IO multiplexing

4惯退、信號(hào)驅(qū)動(dòng)式I/O(SIGIO):signal driven IO

5赌髓、異步I/O(POSIX的aio_系列函數(shù)):asynchronous IO

對(duì)于這五種IO模型,Java并不是一開始就都全部支持催跪,而是有一個(gè)逐步演進(jìn)的過程:

在JDK1.4之前锁蠕,Java的IO模型只支持阻塞式IO(Blocking IO),簡(jiǎn)稱為BIO

在JDK1.4時(shí)懊蒸,支持了I/O多路復(fù)用模型荣倾,相對(duì)于之前的IO模型,這是一個(gè)新的模型骑丸,所以稱之為NIO(New IO)舌仍,有新就有舊,所以有時(shí)也把BIO稱之為OIO(old IO)通危,其實(shí)都是一個(gè)意思铸豁。到現(xiàn)在為止,JDK1.8都已經(jīng)出來了菊碟,JDK1.4時(shí)引入的nio包节芥,也沒有什么新鮮的了,所以更多的人愿意把NIO理解為None-Blocking IO逆害,即非阻塞IO头镊。

在JDK1.7時(shí)增炭,對(duì)NIO包進(jìn)行了升級(jí),支持了異步I/O(Asynchronous IO)拧晕,簡(jiǎn)稱為AIO隙姿,因?yàn)槭菍?duì)nio包的升級(jí),所有有時(shí)又稱之為NIO2.0厂捞。

理解了Java IO模型演進(jìn)與Unix五種IO模型之間的關(guān)系之后输玷,我們對(duì)這五種模型進(jìn)行詳細(xì)的介紹。

在這里靡馁,我們以一個(gè)網(wǎng)絡(luò)IO來舉例:

對(duì)于一個(gè)network IO (以read舉例)欲鹏,它會(huì)涉及到兩個(gè)系統(tǒng)對(duì)象,一個(gè)是調(diào)用這個(gè)IO的進(jìn)程臭墨,另一個(gè)就是系統(tǒng)內(nèi)核(kernel)赔嚎。當(dāng)一個(gè)read操作發(fā)生時(shí),它會(huì)經(jīng)歷兩個(gè)階段:

階段1:等待數(shù)據(jù)準(zhǔn)備 (Waiting for the data to be ready)

階段2:將數(shù)據(jù)從內(nèi)核拷貝到進(jìn)程中 (Copying the data from the kernel to the process)

如果下圖所示:

Image.png

圖中明顯忽略了很多細(xì)節(jié)胧弛,僅顯示了涉及到的基本步驟 尤误,注意圖中用戶空間和內(nèi)核空間的概念。

用戶空間是常規(guī)進(jìn)程所在區(qū)域结缚。 JVM 就是常規(guī)進(jìn)程损晤,駐守于用戶空間。用戶空間是非特權(quán)區(qū)域:比如红竭,在該區(qū)域執(zhí)行的代碼就不能直接訪問硬件設(shè)備尤勋。

內(nèi)核空間是操作系統(tǒng)所在區(qū)域。內(nèi)核代碼有特別的權(quán)力:它能與設(shè)備控制器通訊茵宪,控制著用戶區(qū)域進(jìn)程的運(yùn)行狀態(tài)最冰,等等。最重要的是稀火,所有 I/O 都直接(如這里所述)或間接通過內(nèi)核空間暖哨。

當(dāng)進(jìn)程請(qǐng)求 I/O 操作的時(shí)候,它執(zhí)行一個(gè)系統(tǒng)調(diào)用將控制權(quán)移交給內(nèi)核憾股。C/C++程序員所熟知的底層函數(shù) open( )鹿蜀、 read( )、 write( )和 close( )要做的無非就是建立和執(zhí)行適當(dāng)?shù)南到y(tǒng)調(diào)用服球。當(dāng)內(nèi)核以這種方式被調(diào)用茴恰,它隨即采取任何必要步驟,找到進(jìn)程所需數(shù)據(jù)斩熊,并把數(shù)據(jù)傳送到用戶空間內(nèi)的指定緩沖區(qū)往枣。內(nèi)核試圖對(duì)數(shù)據(jù)進(jìn)行高速緩存或預(yù)讀取,因此進(jìn)程所需數(shù)據(jù)可能已經(jīng)在內(nèi)核空間里了。如果是這樣分冈,該數(shù)據(jù)只需簡(jiǎn)單地拷貝出來即可圾另。如果數(shù)據(jù)不在內(nèi)核空間,則進(jìn)程被掛起雕沉,內(nèi)核著手把數(shù)據(jù)讀進(jìn)內(nèi)存集乔。

了解了這兩個(gè)階段的作用之后,我們接下來就可以深入講解五種IO模型了坡椒,他們的區(qū)別就是在兩個(gè)階段上上有著不同的邏輯扰路。

1、Blocking IO

在linux中倔叼,默認(rèn)情況下所有的socket都是blocking汗唱,一個(gè)典型的讀操作流程大概是這樣:

第一步通常涉及等待數(shù)據(jù)從網(wǎng)絡(luò)中到達(dá)。當(dāng)所有等待數(shù)據(jù)到達(dá)時(shí)丈攒,它被復(fù)制到內(nèi)核中的某個(gè)緩沖區(qū)哩罪。

第二步就是把數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到應(yīng)用程序緩沖區(qū)。

Image.png

當(dāng)用戶進(jìn)程調(diào)用了recvfrom這個(gè)系統(tǒng)調(diào)用巡验,kernel就開始了IO的第一個(gè)階段:準(zhǔn)備數(shù)據(jù)际插。對(duì)于network io來說,很多時(shí)候數(shù)據(jù)在一開始還沒有到達(dá)(比如深碱,還沒有收到一個(gè)完整的UDP包)腹鹉,這個(gè)時(shí)候kernel就要等待足夠的數(shù)據(jù)到來。而在用戶進(jìn)程這邊敷硅,整 個(gè)進(jìn)程會(huì)被阻塞。當(dāng)kernel一直等到數(shù)據(jù)準(zhǔn)備好了愉阎,它就會(huì)將數(shù)據(jù)從kernel中拷貝到用戶內(nèi)存绞蹦,然后kernel返回結(jié)果,用戶進(jìn)程才解除 block的狀態(tài)榜旦,重新運(yùn)行起來幽七。

所以,blocking IO的特點(diǎn)就是在IO執(zhí)行的兩個(gè)階段都被block了溅呢。

2澡屡、非阻塞式I/O

linux下,可以通過設(shè)置socket使其變?yōu)閚on-blocking咐旧。當(dāng)對(duì)一個(gè)non-blocking socket執(zhí)行讀操作時(shí)驶鹉,流程是這個(gè)樣子:

Image.png

從圖中可以看出,當(dāng)用戶進(jìn)程發(fā)出read操作時(shí)铣墨,如果kernel中的數(shù)據(jù)還沒有準(zhǔn)備好室埋,那么它并不會(huì)block用戶進(jìn)程,而是立刻返回一個(gè)error。 從用戶進(jìn)程角度講 姚淆,它發(fā)起一個(gè)read操作后孕蝉,并不需要等待,而是馬上就得到了一個(gè)結(jié)果腌逢。用戶進(jìn)程判斷結(jié)果是一個(gè)error時(shí)降淮,它就知道數(shù)據(jù)還沒有準(zhǔn)備好,于是它可以再次 發(fā)送read操作搏讶。一旦kernel中的數(shù)據(jù)準(zhǔn)備好了佳鳖,并且又再次收到了用戶進(jìn)程的system call,那么它馬上就將數(shù)據(jù)拷貝到了用戶內(nèi)存窍蓝,然后返回腋颠。

所以,用戶進(jìn)程第一個(gè)階段不是阻塞的,需要不斷的主動(dòng)詢問kernel數(shù)據(jù)好了沒有吓笙;第二個(gè)階段依然總是阻塞的淑玫。

3、I/O多路復(fù)用

IO multiplexing這個(gè)詞可能有點(diǎn)陌生面睛,但是如果我說select絮蒿,epoll,大概就都能明白了叁鉴。有些地方也稱這種IO方式為event driven IO土涝。我們都知道,select/epoll的好處就在于單個(gè)process就可以同時(shí)處理多個(gè)網(wǎng)絡(luò)連接的IO幌墓。

IO復(fù)用同非阻塞IO本質(zhì)一樣但壮,不過利用了新的select系統(tǒng)調(diào)用,由內(nèi)核來負(fù)責(zé)本來是請(qǐng)求進(jìn)程該做的輪詢操作常侣±看似比非阻塞IO還多了一個(gè)系統(tǒng)調(diào)用開銷,不過因?yàn)榭梢灾С侄嗦稩O胳施,才算提高了效率溯祸。

它的基本原理就是select /epoll這個(gè)function會(huì)不斷的輪詢所負(fù)責(zé)的所有socket,當(dāng)某個(gè)socket有數(shù)據(jù)到達(dá)了舞肆,就通知用戶進(jìn)程焦辅。它的流程如圖:

Image.png

當(dāng)用戶進(jìn)程調(diào)用了select,那么整個(gè)進(jìn)程會(huì)被block椿胯,而同時(shí)筷登,kernel會(huì)“監(jiān)視”所有select負(fù)責(zé)的socket,當(dāng)任何一個(gè) socket中的數(shù)據(jù)準(zhǔn)備好了压状,select就會(huì)返回仆抵。這個(gè)時(shí)候用戶進(jìn)程再調(diào)用read操作跟继,將數(shù)據(jù)從kernel拷貝到用戶進(jìn)程。

這個(gè)圖和blocking IO的圖其實(shí)并沒有太大的不同镣丑,事實(shí)上舔糖,還更差一些。因?yàn)檫@里需要使用兩個(gè)system call (select 和 recvfrom)莺匠,而blocking IO只調(diào)用了一個(gè)system call (recvfrom)金吗。但是,用select的優(yōu)勢(shì)在于它可以同時(shí)處理多個(gè)connection趣竣。(多說一句摇庙。所以,如果處理的連接數(shù)不是很高的話遥缕,使用 select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好卫袒,可能延遲還更大。

select/epoll的優(yōu)勢(shì)并不是對(duì)于單個(gè)連接能處理得更快单匣,而是在于能處理更多的連接夕凝。

在IO multiplexing Model中,實(shí)際中户秤,對(duì)于每一個(gè)socket码秉,一般都設(shè)置成為non-blocking,但是鸡号,如上圖所示转砖,整個(gè)用戶的process其實(shí)是一直被 block的。只不過process是被select這個(gè)函數(shù)block鲸伴,而不是被socket IO給block府蔗。

4、信號(hào)驅(qū)動(dòng)式I/O

用的很少汞窗,就不做講解了礁竞。直接上圖

Image.png

5、異步I/O

這類函數(shù)的工作機(jī)制是告知內(nèi)核啟動(dòng)某個(gè)操作杉辙,并讓內(nèi)核在整個(gè)操作(包括將數(shù)據(jù)從內(nèi)核拷貝到用戶空間)完成后通知我們。如圖:

Image.png

用戶進(jìn)程發(fā)起read操作之后捶朵,立刻就可以開始去做其它的事蜘矢。而另一方面,從kernel的角度综看,當(dāng)它受到一個(gè)asynchronous read之后品腹,首先它會(huì)立刻返回,所以不會(huì)對(duì)用戶進(jìn)程產(chǎn)生任何block红碑。然后舞吭,kernel會(huì)等待數(shù)據(jù)準(zhǔn)備完成泡垃,然后將數(shù)據(jù)拷貝到用戶內(nèi)存,當(dāng)這一切都 完成之后羡鸥,kernel會(huì)給用戶進(jìn)程發(fā)送一個(gè)signal蔑穴,告訴它read操作完成了。 在這整個(gè)過程中惧浴,進(jìn)程完全沒有被block存和。

總結(jié):

其實(shí)前四種I/O模型都是同步I/O操作,他們的區(qū)別在于第一階段衷旅,而他們的第二階段是一樣的:在數(shù)據(jù)從內(nèi)核復(fù)制到應(yīng)用緩沖區(qū)期間(用戶空間)捐腿,進(jìn)程阻塞于recvfrom調(diào)用。

有人可能會(huì)說释树,non-blocking IO并沒有被block啊容燕。這里有個(gè)非尘判悖“狡猾”的地方,定義中所指的”IO operation”是指真實(shí)的IO操作宪祥,就是例子中的recvfrom這個(gè)system call。non-blocking IO在執(zhí)行recvfrom這個(gè)system call的時(shí)候猪钮,如果kernel的數(shù)據(jù)沒有準(zhǔn)備好品山,這時(shí)候不會(huì)block進(jìn)程。但是烤低,當(dāng)kernel中數(shù)據(jù)準(zhǔn)備好的時(shí)候肘交,recvfrom會(huì)將數(shù)據(jù)從 kernel拷貝到用戶內(nèi)存中,這個(gè)時(shí)候進(jìn)程是被block了扑馁,在這段時(shí)間內(nèi)涯呻,進(jìn)程是被block的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末腻要,一起剝皮案震驚了整個(gè)濱河市复罐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌雄家,老刑警劉巖效诅,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異趟济,居然都是意外死亡乱投,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門顷编,熙熙樓的掌柜王于貴愁眉苦臉地迎上來戚炫,“玉大人,你說我怎么就攤上這事媳纬∷簦” “怎么了施掏?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)茅糜。 經(jīng)常有香客問我七芭,道長(zhǎng),這世上最難降的妖魔是什么限匣? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任抖苦,我火速辦了婚禮,結(jié)果婚禮上米死,老公的妹妹穿的比我還像新娘锌历。我一直安慰自己,他們只是感情好峦筒,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布究西。 她就那樣靜靜地躺著,像睡著了一般物喷。 火紅的嫁衣襯著肌膚如雪卤材。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天峦失,我揣著相機(jī)與錄音扇丛,去河邊找鬼。 笑死尉辑,一個(gè)胖子當(dāng)著我的面吹牛帆精,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播隧魄,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼卓练,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了购啄?” 一聲冷哼從身側(cè)響起襟企,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎狮含,沒想到半個(gè)月后顽悼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡几迄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年表蝙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乓旗。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖集索,靈堂內(nèi)的尸體忽然破棺而出屿愚,到底是詐尸還是另有隱情汇跨,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布妆距,位于F島的核電站穷遂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏娱据。R本人自食惡果不足惜蚪黑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望中剩。 院中可真熱鬧忌穿,春花似錦、人聲如沸结啼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽郊愧。三九已至朴译,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間属铁,已是汗流浹背眠寿。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留焦蘑,地道東北人盯拱。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像喇肋,于是被迫代替她去往敵國和親坟乾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 上一篇《聊聊同步蝶防、異步甚侣、阻塞與非阻塞》[http://www.reibang.com/p/aed6067eeac...
    七寸知架構(gòu)閱讀 140,158評(píng)論 57 445
  • 基本 Linux I/O 模型的簡(jiǎn)單矩陣: 每個(gè) I/O 模型都有自己的使用模式,它們對(duì)于特定的應(yīng)用程序都有自己的...
    faunjoe閱讀 1,514評(píng)論 0 1
  • title: 論事件驅(qū)動(dòng)與異步IOtag: 事件驅(qū)動(dòng) 異步IOcategories: notes 轉(zhuǎn)載自人云思云 ...
    cmustard閱讀 966評(píng)論 0 0
  • 必備的理論基礎(chǔ) 1.操作系統(tǒng)作用: 隱藏丑陋復(fù)雜的硬件接口间学,提供良好的抽象接口殷费。 管理調(diào)度進(jìn)程,并將多個(gè)進(jìn)程對(duì)硬件...
    drfung閱讀 3,546評(píng)論 0 5
  • 注:1)本人非科班出身低葫,文章的來源主要是基于一些能找到的資料详羡,在理解的基礎(chǔ)上做一些總結(jié)歸納,以期對(duì)IO相關(guān)的知識(shí)體...
    Drew_Zhong閱讀 1,017評(píng)論 0 2