NIO的由來,爲什麼需要NIO(一)

 

 

引出下面一段故事......

 

kenny:io包現在已經這麼優雅完美了,別改壞了!

 

kyle:不不不,我們肯定遵循開閉原則(對修改關閉,對擴展開放),所以不會隨意修改io的,那io接口有什麼問題沒有?

 

kenny:除了有人說它過度設計之外,好像沒什麼呀,當你瞭解裝飾模式後你會覺得它還是很好理解的啊。

 

kyle:你不認爲網絡原因或者其他原因碰到阻塞的io會使程序可用性大大降低嗎?

 

kenny:這個我知道,比如我去讀取文件中的一行數據:

當一個線程在執行這段代碼, 遇到readLine()方法的時候, 需要等待數據從硬盤進入內存, 這個線程就會被阻塞,   當然我覺得這也沒啥, 很正常啊, 大家不都是這麼編程的嗎?

 

kyle:不, 有很多人反映了這個問題, 大家想把它改成非阻塞的, 也就是說調用了readLine()方法以後,立刻就返回, 線程就可以幹別的事情去了。

 

kenny:爲什麼要去幹別的事情? 這個線程不就是爲了讀數據嗎?   好,就如你所說, 現在變成了非阻塞的, 調用了readLine()以後, 線程可以執行後面的代碼了, 那這個線程豈不還得做個輪詢操作,看看數據是不是已經讀好了?

這樣一來,代碼多醜陋啊, 不符合我一貫的美學原則, 還不如我原來的阻塞方式呢,我覺得你的要求不可思議。

 

kyle:要是你的線程打開了成百上千個文件呢?  你這種阻塞的方式,只能按照文件1, 文件2, 文件3......   順序的讀取這麼多文件,太慢了.  如果是非阻塞方式, 你可以同時發起成百上千個讀操作(讀操作是由DMA(Direct Memory Access,直接內存讀取),不消耗cpu,非用戶態操作。關於用戶態和內核態下一篇會講到),  然後在那個循環中檢查, 看看誰的數據準備好了,就讀取誰的, 效率多高啊。

 

kenny:誰會那麼傻, 用一個線程打開這麼多文件?肯定開多個線程呀。

 

kyle:那~你聽說過服務器端的Socket編程嗎?

 

kenny:我當然知道, 我還知道這個情況: 一個socket連接來了, 就創建一個新的線程或者從線程池分配一個線程去處理這個連接。

 

kyle:那要是併發連接數太多了怎麼辦?

 

kenny:那就多創建線程唄。

 

kyle:每個線程都會佔用內存空間, 數量多了系統受不了,線程之間的切換也是個要命的開銷啊(線程切換需要cpu在用戶態和內核態之間切換,cpu對於各線程變量或數據的存儲讀取需要消耗大量時間)。

 

kyle看着kenny沉默不語若有所思的樣子,趕緊稱熱打鐵補了一句:

所以大家呼喚非阻塞的方式啊,   讓一個線程管理成百上千個sockcet連接,就像管理多個文件一樣,這樣就不用做線程切換了。

 

kenny:我似乎有點明白了, 正常情況下, 在某一個時刻, 不是每個socket 都有數據讀寫, 很多時候都是空閒的,所以完全可以用輪詢的方式來查看那些socket可以讀寫, 進行操作就可以了。

 

kyle:好吧, 你想怎麼改?

 

總結:

網上關於nio和io的比較都是在比速度,小碼農翻牆查了下外網,發現老外關注的nio並不是速度問題,關於讀取速度面向緩存或者是bio的字節讀取還是nio的塊級讀取,這些都是附加功能,並不是核心,核心是爲了高可用,即可擴展。

       選用宗量還應考慮很多東西:

  • 客戶的生命時間?短期還是長期?

  • 每個客戶預計的數據量?很多小塊或幾塊巨大的塊?

  • 預計會同時連接多少客戶端?

  • 您使用的是什麼操作系統以及您使用的JVM是什麼?這兩個因素分爲線程和輪詢成本。

簡單來說,(長連接)高併發,低帶寬,高擴展,考慮nio;(短連接)低併發,高帶寬,考慮bio即普通io;

關注訂閱號 :一隻可愛的小碼農  加我微信號拉你進java菜雞交流羣,java大廠內推羣,java進階高手羣!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章