標籤:com 產生 傳輸 class www. 裝置 為什麼 作業系統 log
NIO為什麼要使用 NIO?
NIO 的建立目的是為了讓 Java 程式員可以實現高速 I/O 而無需編寫自訂的機器碼。NIO 將最耗時的 I/O 操作(即填充和提取緩衝區)轉移回作業系統,因而可以極大地提高速度。
流與塊的比較
原來的 I/O 庫(在 java.io.*中) 與 NIO 最重要的區別是資料打包和傳輸的方式。正如前面提到的,原來的 I/O 以流的方式處理資料,而 NIO 以塊的方式處理資料。
面向流 的 I/O 系統一次一個位元組地處理資料。一個輸入資料流產生一個位元組的資料,一個輸出資料流消費一個位元組的資料。為流式資料建立過濾器非常容易。連結幾個過濾器,以便每個過濾器只負責單個複雜處理機制的一部分,這樣也是相對簡單的。不利的一面是,面向流的 I/O 通常相當慢。
一個 面向塊 的 I/O 系統以塊的形式處理資料。每一個操作都在一步中產生或者消費一個資料區塊。按塊處理資料比按(流式的)位元組處理資料要快得多。但是面向塊的 I/O 缺少一些面向流的 I/O 所具有的優雅性和簡單性。
NIO的buffer機制
NIO效能的優勢就來源於緩衝的機制,不管是讀或者寫都需要以塊的形式寫入到緩衝區中。NIO實際上讓我們對IO的操作更接近於作業系統的實際過程。
所有的系統I/O都分為兩個階段:等待就緒和操作。舉例來說,讀函數,分為等待系統可讀和真正的讀;同理,寫函數分為等待網卡可以寫和真正的寫。
以socket為例:
先從應用程式層擷取資料到核心的緩衝區,然後再從核心的緩衝區複製到進程的緩衝區。所以實際上底層的機制也是不斷利用緩衝區來讀寫資料的。即使傳統IO抽象成了從流直接讀取資料,但本質上也依然是利用緩衝區來讀取和寫入資料。
所以,為了更好的理解nio,我們就需要知道IO的底層機制,這樣對我們將來理解channel和buffer就打下了基礎。這裡簡單提一下,我們可以把bufffer就理解為核心緩衝區,所以不論讀寫,自然都要經過這個地區,讀的話,先從裝置讀取資料到核心,再讀到進程緩衝區,寫的話,先從進程緩衝區寫到核心,再從核心寫回裝置。
NIO的非阻塞機制
NIO的非阻塞模式,使一個線程從某通道發送請求讀取資料,但是它僅能得到目前可用的資料,如果目前沒有資料可用時,就什麼都不會擷取。而不是保持線程阻塞,所以直至資料變的可以讀取之前,該線程可以繼續做其他的事情。 非阻塞寫也是如此。一個線程請求寫入一些資料到某通道,但不需要等待它完全寫入,這個線程同時可以去做別的事情。 線程通常將非阻塞IO的空閑時間用於在其它通道上執行IO操作,所以一個單獨的線程現在可以管理多個輸入和輸出通道(channel)。
是幾種常見I/O模型的對比:
以socket.read()為例子:
傳統的BIO裡面socket.read(),如果TCP RecvBuffer裡沒有資料,函數會一直阻塞,直到收到資料,返回讀到的資料。
對於NIO,如果TCP RecvBuffer有資料,就把資料從網卡讀到記憶體,並且返回給使用者;反之則直接返回0,永遠不會阻塞。所以我們可以NIO實現同時監聽多個IO通道,然後不斷的輪詢尋找可以讀寫的裝置。
NIO的IO模型可以理解為是IO多工模型和非阻塞模型,同時還有事件驅動模型。
這裡需要知道一點,就是IO多工是一定需要實現非阻塞的。
小結
NIO相對於IO流的優勢:
參考:
- https://tech.meituan.com/nio.html
- http://www.importnew.com/19816.html
- https://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html
【Java】Java NIO