十年架構經驗工程師,帶你讀懂IO/NIO模型

2021-01-19 瘋狂的麥斯基

前言

前段時間公司負責招聘的小姐姐們反應,根據應聘者答題試捲來看這一批應聘者在對IO/NIO理解不是很nice,因此本章主要介紹一下Java IO/NIO相關模型、IO包(NIO包)等內容;具體介紹思路從以下3點來闡述:

IO模型;Java IO;Java NIO;大總結。

IO模型

阻塞IO模型(blocking IO)

最傳統的一種IO模型,即在讀寫數據過程中會發生阻塞現象。當用戶線程發出IO請求之後,內核會去查看數據是否就緒,如果沒有就緒就會等待數據就緒,而用戶線程就會處於阻塞狀態,用戶線程交出CPU。當數據就緒之後,內核會將數據拷貝到用戶線程,並返回結果給用戶線程,用戶線程才解除 block 狀態。典型的阻塞IO模型的例子為: data = socket.read();如果數據沒有就緒,就會一直阻塞在 read()方法。

非阻塞IO模型(non-blocking IO)

當用戶線程發起一個 read 操作後,並不需要等待,而是馬上就得到來一個結果。如果結果是一個error時,它就知道數據還沒有準備好,於是它可以再次發送read操作。一旦內核中的數據準備好了,並且又再次收到了用戶線程的請求,那麼它馬上就將數據拷貝到了用戶線程,然後返回。所以事實上,在非阻塞IO模型中,用戶線程需要不斷的詢問內核數據是否就緒,也就是說非阻塞IO不會交出CPU,而會一直佔有CPU。典型的非阻塞IO模型一般如下:while(true){data = socket.read();if(data != error){// 處理數據 break;}}// 非阻塞IO又一個非常嚴重的問題,在while 循環中需要不斷的去詢問內核數據是否就緒,這樣會導致CPU佔用率非常高,因此一般情況下很少使用while循環這種方式來讀取數據。

多路復用IO模型(IO Multiplex)

多路復用IO模型是目前使用的比較多的模型。Java NIO實際上就是多路復用IO,在多路復用IO模型中會有一個線程不斷去輪詢多個socket的狀態,只有當socket真正有讀寫事件時,才真正調用實際的IO讀寫操作。因為在多路復用IO模型中,只需要使用一個線程就可以管理多個socket,系統不需要建立新的進程或者線程,也不必維護這些線程和進程,並且只有在真正有socket讀寫事件進行時,才會使用IO資源,所有它大大減少資源佔用。在Java NIO中,是通過 selector.select()去查詢每個通道是否有達到事件,如果沒有事件,則一直阻塞在那裡,因此這種方式會導致用戶線程的阻塞。多路復用IO模式,通過一個線程就可以管理多個socket,只有當socket真正有讀寫事件發生才會佔用資源來進行實際的讀寫操作。因此,多路復用IO比較適合連接數比較多的情況另外多路復用IO為何比非阻塞IO模型的效率高?是因為在非阻塞IO中,不斷的詢問socket狀態時通過用戶線程去進行的,而在多路復用IO中,輪詢每個socket狀態是內核在進行的,這個效率要比用戶線程要高的多。不過要注意的是,多路復用IO模型是通過輪詢的方式來檢測是否有事件到達,並且對到達的事件逐一進行響應。因此對於多路復用IO模型來說,一旦事件響應體很大,那麼就會導致後續的事件遲遲得不到處理,並且會影響新的事件輪詢。

信號驅動IO模型(signal driven I/O)

在信號驅動IO模型中,當用戶線程發起一個IO請求操作,會給對應的socket註冊一個信號函數,然後用戶線程會繼續執行,當內核數據就緒時會發送一個信號給用戶線程,用戶線程接收到信號之後,便在信號函數中調用IO讀寫操作來進行實際的IO請求操作。

異步IO模型(asynchronous I/O)

異步IO模型才是最理想的IO模型,在異步IO模型中,當用戶線程發起read操作之後,立刻就可以開始去做其它的事情。而另一方面,從內核的角度,當它受到一個asynchronout read之後,它會立刻返回,說明read請求已經成功發起來,因此不會對用戶線程產生任何block。然後,內核會等待數據準備完成,然後將數據拷貝到用戶線程,當這一切都完成之後,內核會給用戶線程發送一個信號,告訴它read操作完成了。也就是說用戶線程完全不需要實際的整個IO操作是如何進行的,只需要發起一個請求,當接收內核返回的成功信號時表示IO操作已完成,可以直接去使用數據了。也就是說在異步IO模型中,IO操作的兩個階段都不會阻塞用戶線程,這兩個階段都是由內核自動完成,然後發送一個信號告知用戶線程操作已完成。用戶線程中不需要再次調用IO函數進行具體的讀寫。這點是和信號驅動模型有所不同的,在信號驅動模型中,當用戶線程接收到信號表示數據已經就緒,然後需要用戶線程調用IO函數進行實際的讀寫操作;而在異步IO模型中,收到信號表示IO操作已經完成,不需要再在用戶線程中調用IO函數進行實際的讀寫操作。注意,異步IO是需要作業系統的底層支持,在Java 7中,提供了Asynchronous IO。

Java IO包

Java IO包統計

Java NIO

什麼是Java NIO?

java.nio全稱java non-blocking IO(實際上是 new io),是指JDK 1.4 及以上版本裡提供的新api(New IO),為所有的原始類型(boolean類型除外)提供緩存支持的數據容器,使用它可以提供非阻塞式的高伸縮性網絡。

NIO三大核心部分?

Channel(通道);Buffer(緩衝區);Selector選擇區。IO和NIO區別?

傳統 IO 是面向流、阻塞的,NIO 則是面向緩衝區、非阻塞的。

傳統IO基於字節流和字符流進行操作,而NIO基於Channel和Buffer進行操作,數據總是從通道讀取到緩衝區中,或者從緩衝區寫入到通道中。Selector用於監聽多個通道的事件(比如:連接打開、數據到達)。因此,單個線程可以監聽多個數據通道。

NIO的緩衝區

Java IO面向流意味這每次從流中讀一個或多個字節,直至讀取所有字節,它們沒有被緩存在任何地方。此外,它不能前後移動流中的數據。如果需要前後移動從流中讀取的數據,需要先將它緩存到一個緩衝區。NIO的緩衝導向方法不同,數據讀取到一個它稍後處理的緩衝區,需要時可在緩衝區中前後移動。這就增加了處理過程中的靈活性。但是,還需要檢查是否該緩衝區中包含所有你需要處理的數據。而且,需確保當更多的數據讀入緩衝區時,不要覆蓋緩衝區裡尚未處理的數據。

NIO的非阻塞

IO的各種流是阻塞的,這意味著,當一個線程調用read()或write()時,該線程被阻塞,直到有一些數據被讀取,或數據完全寫入。該線程在此期間不能再幹任何事情流。NIO的非阻塞模式,使一個線程從某通道發送請求讀取數據,但是它僅能得到目前可用的數據,如果目前沒有數據可用時,就什麼都不會獲取。而不是保持線程阻塞,所有直至數據變得可以讀取之前,該線程可以繼續做其它的事情。給阻塞寫也是如此。一個線程請求寫入一些數據到某通道,但不需要等待它完全寫入,這個線程同時可以去做別的事情。線程通常將非阻塞IO的空閒時間用於在其它通道上執行IO操作,所以一個單獨的線程現在可以管理多個輸入和輸出通道(channel)。

Java NIO包統計

ChannelChannel和IO中Stream是差不多一個等級的。只不過Stream是單向的,譬如:InputStream,OutputStream,而Channel是雙向的,既可以用來進行讀操作,又可以用來寫操作。

NIO中Channel的主要實現有:

FileChannelDatagramChannelSocketChannelServerSocketChannelBufferBuffer緩衝區,實際上是一個容器,是一個連續數組。Channel提供從文件、網絡讀取數據的渠道,但是讀取或寫入的數據都必須經由Buffer。

上圖描述來從一個客戶段想服務端發送數據,然後服務端就收數據的過程。客戶端發送數據時,必須先將數據存入Buffer中,然後將Buffer中的內容寫入通道。服務端這邊接收數據必須通過Channel將數據讀入到Buffer中,然後再從Buffer中取出數據來處理。

在NIO中,Buffer是一個頂層父類,它是一個抽象類,常用的buffer的子類有:ByteBuffer、IntBuffer、CharBuffer、CharBuffer、LongBuffer、DoubleBuffer、FloatBuffer、ShortBuffer。

SelectorSelector類是NIO的核心類,Selector能夠檢測多個註冊的通道上是否有事件發生,如果有事件發生,便獲取事件然後針對每個事件進行相應的響應處理。這樣一來,只是用一個但線程就可以管理多個通道,也就是管理多個連接。這樣使得只有在連接真正有讀寫事件發生時,才會調用函數來進行讀寫,就大大地減少來系統開銷,並且不必為每個連接都創建一個線程,不用去維護多個線程,並且避免來多線程之間的上下文切換導致的開銷。

大總結

blocking I/O,數據準備、數據copy 全阻塞,同步阻塞IO;nonblocking I/O,數據準備不阻塞,數據copy阻塞,非阻塞IO;I/O multiplexing,數據準備阻塞,數據copy阻塞,多路復用IO,優點可以支持更多IO請求;signal driven I/O (SIGIO),數據準備不阻塞,數據copy阻塞,異步阻塞IO;asynchronous I/O,數據準備、數據copy 全部阻塞。異步非阻塞IO。結尾

小夥伴們,此章主要是介紹的理論知識,還有一些代碼未附上,由於本人文字功底不好文中表達不清楚的望請各位小夥伴們見諒。

相關焦點

  • 一圖讀懂什麼是Gate.io芝麻開門牛熊證
    Gate.io芝麻開門牛熊證是一種提供看漲和看跌選擇的槓槓衍生品。Gate.io芝麻開門牛熊證的特點:1.現貨式簡單操作:牛熊證交易類似於現貨的買入賣出,無需保證金和其它操作,看漲買牛看跌買熊即可;2.高槓桿屬性:牛熊證具有槓桿高屬性,極端行情最高可達100-200倍;3.手續費低廉:與現貨以及合約比較,牛熊證交易手續費更低
  • 15 年架構設計經驗:我眼中的那些優秀架構師
    去年底,我曾經面試過一位架構師的候選人。這位候選人是一位大廠高級工程師,因為技術好,在團隊中承擔一些管理工作。從他簡歷上的項目經驗,我能看出他的編程能力和技術深度都屬於優秀行列,在某些項目上,已經承擔了一部分架構設計職責,是個潛力型人選。
  • NIO&AIO編程模型
    NIO線程模型什麼是NIO線程模型?上圖是NIO的線程模型, 基於select實現, 這種線程模型的特點: 多條channel通過一個選擇器和單挑線程綁定, 並且在這種編程模型中, Channel中相關業務邏輯不允許存在耗時的任務 , 如果一定會有耗時的邏輯, 請將它們放置到線程池中去運行, 因為這種模型雖然做到了非阻塞, 但是他並不是真正的異步編程, 任何channel上的任何耗時的操作, 都會拖垮這個選擇器
  • 阿里架構師直通車:Netty+NIO+Redis+Kafka共計13.62G,一鍵入職
    此外,如果您有Java方面的經驗,您可以快速入門。這些框架都使用相同的語法,使用相似的術語、範例和概念。了解過Java架構的小夥伴一定都知道Netty+NIO+Zookeeper+Kafka+Redis這幾種架構師必學的開源框架以及資料庫吧。
  • NIO、BIO、AIO、同步異步、阻塞非阻塞傻傻分不清楚?
    同步IO異步IONIO與BIO的區別總結NIOBIO基於緩衝區( Buffer )基於流( Stream )非阻塞 IO阻塞 IO選擇器( Selector )無BIOBlocking IO,是同步阻塞的IO模型,傳統的IO【java.io包】就是這種模型。
  • 64 Audio Nio & 索尼Z1R 燒友詳盡對比橫評
    其實我手裡還有別的耳塞,土豪那裡設備更多,但天氣實在太熱,懶得帶太多,各自一套倆倆交換互聽順便交流經驗,收穫還是不少。以前從未接觸過64audio這個牌子,可能是名字太過和諧,總有一種距離感,能這樣起名的百分百是洋牌子,結果聽起來卻有一種「亞洲器材」的味道。這耳塞首先抓耳的是人聲。
  • Java中的IO與NIO
    JSR 51 的實現,其結果就是新增類組合到一起,構成了 java.nio 及其子包,以及 java.util.regex 軟體包,同時現存軟體包也相應作了幾處修改。JCP 網站詳細介紹了 JSR 的運作流程,以及 NIO 從最初的提議到最終實現並發布的演進歷程。隨著 Merlin(Jdk1.4) 的發布,作業系統強大的IO特性終於可以藉助 Java 提供的工具得到充分發揮。
  • Dailyio 年終巨獻:萬字長文讀懂 2020 全球 AI 領域的十大關鍵詞
    以下文章來源於Dailyio ,作者趙賽坡 江蘇雷射聯盟轉載江蘇雷射聯盟推薦 來源:Dailyio作者:趙賽坡【江蘇雷射聯盟寫在前面】2020 年大幕即將落下,這場貫穿一年、橫掃全球的疫情深刻改變了這個世界的走向,機器人與雲服務需求激增、遠程辦公普遍化......這些上一年聽起來還過於樂觀的預測,如今幾乎已經深入到各個行業
  • 中科院遙感與數字地球研究所大數據架構師、大數據研發工程師招聘9...
    現因項目的研發的需求,公開招聘大數據研發架構師、大數據研發工程師以及大數據前端工程師若干名。計算機、信息系統、數學、工程類全日制本科以上學歷,8年以上軟體研發經驗,5年以上大數據平臺研發經驗;2. 掌握常用的軟體設計方法、計算架構和解決方案,熟練使用Scala/Java的Spark開發,熟悉Python、JavaScript等web開發技術,有空間數據處理與分析平臺開發經驗者優先;3.
  • 一文帶你了解推薦系統架構
    4、文末有驚喜哦~前言你是否想過有一天,你看到自己的身體被無數的數據所組合,歷史10%,經濟23%,財經12%……你仔細一看,有些數據竟然連你都從未注意。當你對新的信息作出反應的時候,你的各個興趣點發生了變化,有的權重增高,有的權重降低。
  • 面向領域的微服務架構
    我們介紹DOMA的目的是為了給那些希望降低整體系統複雜性,同時又保持微服務架構相關靈活性的組織提供一些經驗建議。這篇文章主要解釋了什麼是DOMA,以及Uber採用這種架構的原因,它對平臺和產品團隊帶來哪些好處。最後,給想要採用這種架構的團隊一些建議。什麼是微服務微服務是面向服務架構的延伸。
  • 阿里技術官分享Java架構師成長筆記,帶你一步一腳印修成正果
    關於內容本書是作者多年Java軟體架構實踐與研究的經驗總結,包含架構設計的8項原則,21種設計技巧,25個溫馨提示,39個實戰經典案例,架構測試以及開源軟體設計、開發、發布等知識,同時還包括架構自動化代碼工具的設計與開發技能。其內容詳實、條理清晰、圖文並茂、實戰性強一切都圍繞提高讀者軟體架構實戰技能。
  • 做一名「擰螺絲」的架構師
    我想,就是從架構師的思維層次上,做好每一件小事。我們常常稱網際網路大廠的工作是「面試造火箭,入職擰螺絲」,雖然客觀上確實如此,但一家公司之中,造火箭的架構師往往不需要太多的人,但需要大量懂火箭的工程師。架構是一種思維方式,思維方式是可被訓練的,只有大量能夠思考到未來發展的工程師凝聚在一起,一家公司才有了技術力量的「靈魂」。
  • 3 個重要因素,帶你看透 AI 技術架構方案的可行性
    無論是在新業務上的嘗試,還是對舊有業務對改造升級,AI這個奔湧了60多年的「後浪」,正潛移默化的影響著我們傳統的技術架構觀念。AI架構(尤其是以機器學習和深度學習為代表的架構方案)已經成為我們技術架構選型中的一個新的選項。你是否需要AI架構的解決方案?AI架構選型的主要依據是什麼?
  • 30分鐘帶你了解Web工程師必知的Docker知識
    本文主要會介紹Docker的基礎知識和應用領域,並通過實際部署一個web項目來帶大家了解Docker的使用方式。作為一名前端工程師,為什麼要學習Docker呢?做過B端系統或有Saas系統開發經驗的朋友也許會清楚其中的繁瑣,為了客戶安全和私有化往往需要研發人員給企業配置和部署獨立的Web應用,如果你有上百家客戶上千家客戶,我們一個個部署顯然是效率極低的,而且不能保證環境的一致性和穩定性,因為一旦我們的Web系統使用的環境或者包更新了,應用很可能不能正常Work,這種情況下採用Docker容器化技術可以很好的解決這一問題。
  • 流程圖設計入門指南——以 Draw.io 為例
    Draw.io基本繪圖操作三. 基本流程圖繪製1.簡單流程圖模板上圖展示了結構簡單的流程圖模板, 包含了幾個關鍵點:基本形狀: 包括開始 [Start](圓形或橢圓形) 和結束 [Terminator]、處理步驟 [Process](矩形)、判斷條件 [Decision](菱形)、子流程/或多個步驟集合(圖示的橙色帶豎線矩形,此圖形在 General 圖形集合面板), 總結起來就是有始有終, 有步驟有循環關鍵文字標識:
  • 那些已經入手64 Audio Nio的燒友,現在還好嗎?
    ,原線下的nio聲音較為均衡,聽流行很舒服,換原廠升級線後nio的素質有了很大的提升,聲音相對原線更加細膩,低頻量相對原線削了很多,更加突出中高頻段,總體來說nio+原廠升級線更加適合偏器樂的聲音。此外,nio對於前端的選擇也做的較為有包容性,即使是那些入門級的前端也能推出像模像樣的聲音,總之,nio在萬元塞裡絕對是佼佼者,這是我盲狙的塞子裡為數不多的能讓我不後悔的耳機。
  • 從月薪3K到年薪百萬,運維工程師職業晉升之路,全幫你規劃好了!
    無論你是個剛入職沒幾個月的行業新人,還是在行業裡摸爬打滾了好幾年的「老鳥」。你都面對著同樣殘酷的一個現實:這是一個高速發展的行業,任何肚子裡沒有實貨的技術人員都會被這個圈子所淘汰。那麼,做運維的你,最終的出路到底在哪裡呢?到底怎麼樣才能出人頭地,拿到一個年薪百萬的Offer?
  • 機械工程師知識架構—了解80%以上的都是鳳毛麟角
    機械行業水很深,要想成大師,需要學習和了解的知識可以說一輩子都學不完的,當然具體也會細分很多不同的領域,不同領域所需要的知識也不同,當然了解的越多對於個人設計能力來說會有好處,也會提高你的眼界,使得你所設計的產品更加合理,更加經濟,多做多看多思考,探索精神和自主學習能力,更要多看相關的機械設計案例,機械設計手冊平時也要多看,注意平時的積累
  • 如何0代碼、快速定製企業級NLP模型?百度工程師詳解技術選型與模型...
    主講人 | 龍心塵 百度NLP資深研發工程師量子位編輯 | 公眾號 QbitAI近幾年以預訓練為代表的NLP技術取得了爆發式發展,新技術新模型層出不窮。企業與開發者如何將最先進的NLP領域科研成果,高效地應用到業務場景中並解決實際問題?