說一下BIO/AIO/NIO 有什么區(qū)別?及異步模式的用途和意義

涕烧?

1F

說一說I/O
首先來說一下什么是I/O?

在計(jì)算機(jī)系統(tǒng)中I/O就是輸入(Input)和輸出(Output)的意思月而,針對不同的操作對象,可以劃分為磁盤I/O模型议纯,網(wǎng)絡(luò)I/O模型父款,內(nèi)存映射I/O, Direct I/O、數(shù)據(jù)庫I/O等瞻凤,只要具有輸入輸出類型的交互系統(tǒng)都可以認(rèn)為是I/O系統(tǒng)铛漓,也可以說I/O是整個操作系統(tǒng)數(shù)據(jù)交換與人機(jī)交互的通道,這個概念與選用的開發(fā)語言沒有關(guān)系鲫构,是一個通用的概念浓恶。

在如今的系統(tǒng)中I/O卻擁有很重要的位置,現(xiàn)在系統(tǒng)都有可能處理大量文件结笨,大量數(shù)據(jù)庫操作包晰,而這些操作都依賴于系統(tǒng)的I/O性能,也就造成了現(xiàn)在系統(tǒng)的瓶頸往往都是由于I/O性能造成的炕吸。因此伐憾,為了解決磁盤I/O性能慢的問題,系統(tǒng)架構(gòu)中添加了緩存來提高響應(yīng)速度赫模;或者有些高端服務(wù)器從硬件級入手树肃,使用了固態(tài)硬盤(SSD)來替換傳統(tǒng)機(jī)械硬盤;在大數(shù)據(jù)方面瀑罗,Spark越來越多的承擔(dān)了實(shí)時(shí)性計(jì)算任務(wù)胸嘴,而傳統(tǒng)的Hadoop體系則大多應(yīng)用在了離線計(jì)算與大量數(shù)據(jù)存儲的場景,這也是由于磁盤I/O性能遠(yuǎn)不如內(nèi)存I/O性能而造成的格局(Spark更多的使用了內(nèi)存斩祭,而MapReduece更多的使用了磁盤)劣像。因此,一個系統(tǒng)的優(yōu)化空間摧玫,往往都在低效率的I/O環(huán)節(jié)上耳奕,很少看到一個系統(tǒng)CPU、內(nèi)存的性能是其整個系統(tǒng)的瓶頸。也正因?yàn)槿绱宋萑海琂ava在I/O上也一直在做持續(xù)的優(yōu)化闸婴,從JDK 1.4開始便引入了NIO模型,大大的提高了以往BIO模型下的操作效率芍躏。

這里先給出BIO邪乍、NIO、AIO的基本定義與類比描述:

BIO (Blocking I/O):同步阻塞I/O模式纸肉,數(shù)據(jù)的讀取寫入必須阻塞在一個線程內(nèi)等待其完成溺欧。這里使用那個經(jīng)典的燒開水例子喊熟,這里假設(shè)一個燒開水的場景柏肪,有一排水壺在燒開水,BIO的工作模式就是芥牌, 叫一個線程停留在一個水壺那烦味,直到這個水壺?zé)_,才去處理下一個水壺壁拉。但是實(shí)際上線程在等待水壺?zé)_的時(shí)間段什么都沒有做谬俄。

NIO (New I/O):同時(shí)支持阻塞與非阻塞模式,但這里我們以其同步非阻塞I/O模式來說明弃理,那么什么叫做同步非阻塞溃论?如果還拿燒開水來說,NIO的做法是叫一個線程不斷的輪詢每個水壺的狀態(tài)痘昌,看看是否有水壺的狀態(tài)發(fā)生了改變钥勋,從而進(jìn)行下一步的操作。

AIO ( Asynchronous I/O):異步非阻塞I/O模型辆苔。異步非阻塞與同步非阻塞的區(qū)別在哪里算灸?異步非阻塞無需一個線程去輪詢所有IO操作的狀態(tài)改變,在相應(yīng)的狀態(tài)改變后驻啤,系統(tǒng)會通知對應(yīng)的線程來處理菲驴。對應(yīng)到燒開水中就是,為每個水壺上面裝了一個開關(guān)骑冗,水燒開之后赊瞬,水壺會自動通知我水燒開了。

進(jìn)程中的IO調(diào)用步驟大致可以分為以下四步:

進(jìn)程向操作系統(tǒng)請求數(shù)據(jù) ;

操作系統(tǒng)把外部數(shù)據(jù)加載到內(nèi)核的緩沖區(qū)中;

操作系統(tǒng)把內(nèi)核的緩沖區(qū)拷貝到進(jìn)程的緩沖區(qū) ;

進(jìn)程獲得數(shù)據(jù)完成自己的功能 ;

當(dāng)操作系統(tǒng)在把外部數(shù)據(jù)放到進(jìn)程緩沖區(qū)的這段時(shí)間(即上述的第二贼涩,三步)森逮,如果應(yīng)用進(jìn)程是掛起等待的,那么就是同步IO磁携,反之褒侧,就是異步IO,也就是AIO 。

2F

BIO(Blocking I/O)同步阻塞I/O
這是最基本與簡單的I/O操作方式闷供,其根本特性是做完一件事再去做另一件事烟央,一件事一定要等前一件事做完,這很符合程序員傳統(tǒng)的順序來開發(fā)思想歪脏,因此BIO模型程序開發(fā)起來較為簡單疑俭,易于把握。

但是BIO如果需要同時(shí)做很多事情(例如同時(shí)讀很多文件婿失,處理很多tcp請求等)钞艇,就需要系統(tǒng)創(chuàng)建很多線程來完成對應(yīng)的工作,因?yàn)锽IO模型下一個線程同時(shí)只能做一個工作豪硅,如果線程在執(zhí)行過程中依賴于需要等待的資源哩照,那么該線程會長期處于阻塞狀態(tài),我們知道在整個操作系統(tǒng)中懒浮,線程是系統(tǒng)執(zhí)行的基本單位飘弧,在BIO模型下的線程 阻塞就會導(dǎo)致系統(tǒng)線程的切換,從而對整個系統(tǒng)性能造成一定的影響砚著。當(dāng)然如果我們只需要創(chuàng)建少量可控的線程次伶,那么采用BIO模型也是很好的選擇,但如果在需要考慮高并發(fā)的web或者tcp服務(wù)器中采用BIO模型就無法應(yīng)對了稽穆,如果系統(tǒng)開辟成千上萬的線程冠王,那么CPU的執(zhí)行時(shí)機(jī)都會浪費(fèi)在線程的切換中,使得線程的執(zhí)行效率大大降低舌镶。此外柱彻,關(guān)于線程這里說一句題外話,在系統(tǒng)開發(fā)中線程的生命周期一定要準(zhǔn)確控制乎折,在需要一定規(guī)模并發(fā)的情形下绒疗,盡量使用線程池來確保線程創(chuàng)建數(shù)目在一個合理的范圍之內(nèi),切莫編寫線程數(shù)量創(chuàng)建上限的代碼骂澄。

3F

NIO (New I/O) 同步非阻塞I/O
關(guān)于NIO吓蘑,國內(nèi)有很多技術(shù)博客將英文翻譯成No-Blocking I/O,非阻塞I/O模型 坟冲,當(dāng)然這樣就與BIO形成了鮮明的特性對比磨镶。NIO本身是基于事件驅(qū)動的思想來實(shí)現(xiàn)的,其目的就是解決BIO的大并發(fā)問題健提,在BIO模型中琳猫,如果需要并發(fā)處理多個I/O請求,那就需要多線程來支持私痹,NIO使用了多路復(fù)用器機(jī)制脐嫂,以socket使用來說统刮,多路復(fù)用器通過不斷輪詢各個連接的狀態(tài),只有在socket有流可讀或者可寫時(shí)账千,應(yīng)用程序才需要去處理它侥蒙,在線程的使用上,就不需要一個連接就必須使用一個處理線程了匀奏,而是只是有效請求時(shí)(確實(shí)需要進(jìn)行I/O處理時(shí))鞭衩,才會使用一個線程去處理,這樣就避免了BIO模型下大量線程處于阻塞等待狀態(tài)的情景娃善。

相對于BIO的流论衍,NIO抽象出了新的通道(Channel)作為輸入輸出的通道,并且提供了緩存(Buffer)的支持聚磺,在進(jìn)行讀操作時(shí)坯台,需要使用Buffer分配空間,然后將數(shù)據(jù)從Channel中讀入Buffer中咧最,對于Channel的寫操作捂人,也需要現(xiàn)將數(shù)據(jù)寫入Buffer御雕,然后將Buffer寫入Channel中矢沿。

如下是NIO方式進(jìn)行文件拷貝操作的示例,見下圖:


在這里插入圖片描述

通過比較New IO的使用方式我們可以發(fā)現(xiàn)酸纲,新的IO操作不再面向 Stream來進(jìn)行操作了捣鲸,改為了通道Channel,并且使用了更加靈活的緩存區(qū)類Buffer闽坡,Buffer只是緩存區(qū)定義接口栽惶, 根據(jù)需要,我們可以選擇對應(yīng)類型的緩存區(qū)實(shí)現(xiàn)類疾嗅。在java NIO編程中外厂,我們需要理解以下3個對象Channel、Buffer和Selector代承。

  • Channel

首先說一下Channel汁蝶,國內(nèi)大多翻譯成“通道”。Channel和IO中的Stream(流)是差不多一個等級的论悴。只不過Stream是單向的掖棉,譬如:InputStream, OutputStream。而Channel是雙向的膀估,既可以用來進(jìn)行讀操作幔亥,又可以用來進(jìn)行寫操作,NIO中的Channel的主要實(shí)現(xiàn)有:FileChannel察纯、DatagramChannel帕棉、SocketChannel针肥、ServerSocketChannel;通過看名字就可以猜出個所以然來:分別可以對應(yīng)文件IO香伴、UDP和TCP(Server和Client)祖驱。

  • Buffer

NIO中的關(guān)鍵Buffer實(shí)現(xiàn)有:ByteBuffer、CharBuffer瞒窒、DoubleBuffer捺僻、 FloatBuffer、IntBuffer崇裁、 LongBuffer,匕坯、ShortBuffer,分別對應(yīng)基本數(shù)據(jù)類型: byte拔稳、char葛峻、double、 float巴比、int术奖、 long、 short轻绞。當(dāng)然NIO中還有MappedByteBuffer, HeapByteBuffer, DirectByteBuffer等這里先不具體陳述其用法細(xì)節(jié)采记。

說一下 DirectByteBuffer 與 HeapByteBuffer 的區(qū)別?

它們 ByteBuffer 分配內(nèi)存的兩種方式政勃。HeapByteBuffer 顧名思義其內(nèi)存空間在 JVM 的 heap(堆)上分配唧龄,可以看做是 jdk 對于 byte[] 數(shù)組的封裝;而 DirectByteBuffer 則直接利用了系統(tǒng)接口進(jìn)行內(nèi)存申請奸远,其內(nèi)存分配在c heap 中既棺,這樣就減少了內(nèi)存之間的拷貝操作,如此一來懒叛,在使用 DirectByteBuffer 時(shí)丸冕,系統(tǒng)就可以直接從內(nèi)存將數(shù)據(jù)寫入到 Channel 中,而無需進(jìn)行 Java 堆的內(nèi)存申請薛窥,復(fù)制等操作胖烛,提高了性能。既然如此拆檬,為什么不直接使用 DirectByteBuffer洪己,還要來個 HeapByteBuffer?原因在于竟贯, DirectByteBuffer 是通過full gc來回收內(nèi)存的答捕,DirectByteBuffer會自己檢測情況而調(diào)用 system.gc(),但是如果參數(shù)中使用了 DisableExplicitGC 那么就無法回收該快內(nèi)存了屑那,-XX:+DisableExplicitGC標(biāo)志自動將 System.gc() 調(diào)用轉(zhuǎn)換成一個空操作拱镐,就是應(yīng)用中調(diào)用 System.gc() 會變成一個空操作艘款,那么如果設(shè)置了就需要我們手動來回收內(nèi)存了,所以DirectByteBuffer使用起來相對于完全托管于 java 內(nèi)存管理的Heap ByteBuffer 來說更復(fù)雜一些沃琅,如果用不好可能會引起OOM哗咆。Direct ByteBuffer 的內(nèi)存大小受 -XX:MaxDirectMemorySize JVM 參數(shù)控制(默認(rèn)大小64M),在 DirectByteBuffer 申請內(nèi)存空間達(dá)到該設(shè)置大小后益眉,會觸發(fā) Full GC晌柬。

  • Selector

Selector 是NIO相對于BIO實(shí)現(xiàn)多路復(fù)用的基礎(chǔ),Selector 運(yùn)行單線程處理多個 Channel郭脂,如果你的應(yīng)用打開了多個通道年碘,但每個連接的流量都很低,使用 Selector 就會很方便展鸡。例如在一個聊天服務(wù)器中屿衅。要使用 Selector , 得向 Selector 注冊 Channel,然后調(diào)用它的 select() 方法莹弊。這個方法會一直阻塞到某個注冊的通道有事件就緒涤久。一旦這個方法返回,線程就可以處理這些事件忍弛,事件的例子有如新的連接進(jìn)來响迂、數(shù)據(jù)接收等。

這里我們再來看一個NIO模型下的TCP服務(wù)器的實(shí)現(xiàn)剧罩,我們可以看到Selector 正是NIO模型下 TCP Server 實(shí)現(xiàn)IO復(fù)用的關(guān)鍵栓拜,請仔細(xì)理解下段代碼while循環(huán)中的邏輯座泳,見下圖:


在這里插入圖片描述

4F

AIO (Asynchronous I/O) 異步非阻塞I/O
Java AIO就是Java作為對異步IO提供支持的NIO.2 惠昔,Java NIO2 (JSR 203)定義了更多的 New I/O APIs, 提案2003提出挑势,直到2011年才發(fā)布镇防, 最終在JDK 7中才實(shí)現(xiàn)。JSR 203除了提供更多的文件系統(tǒng)操作API(包括可插拔的自定義的文件系統(tǒng))潮饱, 還提供了對socket和文件的異步 I/O操作来氧。 同時(shí)實(shí)現(xiàn)了JSR-51提案中的socket channel全部功能,包括對綁定, option配置的支持以及多播multicast的實(shí)現(xiàn)香拉。

從編程模式上來看AIO相對于NIO的區(qū)別在于啦扬,NIO需要使用者線程不停的輪詢IO對象,來確定是否有數(shù)據(jù)準(zhǔn)備好可以讀了凫碌,而AIO則是在數(shù)據(jù)準(zhǔn)備好之后扑毡,才會通知數(shù)據(jù)使用者,這樣使用者就不需要不停地輪詢了盛险。當(dāng)然AIO的異步特性并不是Java實(shí)現(xiàn)的偽異步瞄摊,而是使用了系統(tǒng)底層API的支持勋又,在Unix系統(tǒng)下,采用了epoll IO模型换帜,而windows便是使用了IOCP模型楔壤。關(guān)于Java AIO,本篇只做一個拋磚引玉的介紹惯驼,如果你在實(shí)際工作中用到了蹲嚣,那么可以參考Netty在高并發(fā)下使用AIO的相關(guān)技術(shù)。

總 結(jié)

IO實(shí)質(zhì)上與線程沒有太多的關(guān)系祟牲,但是不同的IO模型改變了應(yīng)用程序使用線程的方式端铛,NIO與AIO的出>現(xiàn)解決了很多BIO無法解決的并發(fā)問題,當(dāng)然任何技術(shù)拋開適用場景都是耍流氓疲眷,復(fù)雜的技術(shù)往往是為了解決簡單技術(shù)無法解決的問題而設(shè)計(jì)的禾蚕,在系統(tǒng)開發(fā)中能用常規(guī)技術(shù)解決的問題,絕不用復(fù)雜技術(shù)狂丝,>否則大大增加系統(tǒng)代碼的維護(hù)難度换淆,學(xué)習(xí)IT技術(shù)不是為了炫技,而是要實(shí)實(shí)在在解決問題几颜。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末倍试,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蛋哭,更是在濱河造成了極大的恐慌县习,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谆趾,死亡現(xiàn)場離奇詭異躁愿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)沪蓬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門彤钟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人跷叉,你說我怎么就攤上這事逸雹。” “怎么了云挟?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵梆砸,是天一觀的道長。 經(jīng)常有香客問我园欣,道長帖世,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任俊庇,我火速辦了婚禮狮暑,結(jié)果婚禮上鸡挠,老公的妹妹穿的比我還像新娘。我一直安慰自己搬男,他們只是感情好拣展,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缔逛,像睡著了一般备埃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上褐奴,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天按脚,我揣著相機(jī)與錄音,去河邊找鬼敦冬。 笑死辅搬,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的脖旱。 我是一名探鬼主播堪遂,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼萌庆!你這毒婦竟也來了溶褪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤践险,失蹤者是張志新(化名)和其女友劉穎猿妈,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體巍虫,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡彭则,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了垫言。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贰剥。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖筷频,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情前痘,我是刑警寧澤凛捏,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站芹缔,受9級特大地震影響坯癣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜最欠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一示罗、第九天 我趴在偏房一處隱蔽的房頂上張望惩猫。 院中可真熱鬧,春花似錦蚜点、人聲如沸轧房。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奶镶。三九已至,卻和暖如春陪拘,著一層夾襖步出監(jiān)牢的瞬間厂镇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工左刽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捺信,地道東北人。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓欠痴,卻偏偏與公主長得像残黑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子斋否,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355

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