1. 程式人生 > 程式設計 >BIO、NIO與AIO

BIO、NIO與AIO

本文主要講解NIO

BIO(Blocking I/O) -- 阻塞IO

1. 不管是從本地還是從網路上使用InputStream來讀取或則使用OutputStream來寫入資料時,都有可能被阻塞掉,從而失去對CPU的使用權,當遇到大規模的訪問量和對效能有較高要求的時候,這種方式及顯示力不從心了。

2. 當然也可以使用多個執行緒來處理多個請求,甚至是可以使用執行緒池來提高服務端的效能。但這樣的話,又會產生很多問題,比如我們通過給執行緒設定優先順序來實現服務更高優先順序時就難以完成。

3. 除此之外,這些執行緒難免會涉及到訪問競爭資源的問題,去同時處理多個執行緒資源競爭問題比處理單個執行緒複雜得多。=>所以NIO應運而生。

NIO(non-blocking I/O) -- 非阻塞IO

NIO概述

NIO主要包含有三個主要構件Selector,Channel,Buffer。

1. Channel就相當於傳輸資料的一個通道,Buffer就相當於通道中具體用來傳輸資料的運載體,Selector就相當於用於排程管理通道的一個排程管理器。

2. 在以往BIO中,程式設計師只能看到兩個東西Stream和Socket,而不能操縱它們內部資料傳輸方式。

3. 而NIO中,Buffer就好比Stream的具體化,可以讓程式設計師來進行控制資料傳送/接受長度,比如使用BIO時,使用write方法對sendQ進行寫資料,當一次寫入的資料長度超過sendQ長度時,還需要對傳入的資料進行分割,分割這個資料就是最耗時的時候了,資料需要從使用者空間到核心空間的切換,這個切換過程程式設計師是無法控制的。但使用NIO的Buffer來控制Buffer的容量,是否擴容,如何擴容來有效避免資料空間切換的成本消耗。

* 其中sendQ不懂得可以去看看計算機網路 TCP的接受/傳送佇列

4. 由於Socket封裝了資訊,我們不知道在傳輸過程中有多少資料傳輸了,有多少沒傳輸,但通過Channel我們可以知道這個通道還能夠繼續傳輸多少資料。再者我們還可以通過selector監控所有已經註冊到排程器上的通道。

使用NIO的例子 -- 各個部分的意思也註釋在程式碼中

這位大佬寫的例子就十分清晰例子

NIO中重點 -- Buffer工作方式

1. 四個重要索引:

image

2. 在實際運用中比如:


//建立一個24個的byte陣列緩衝區,初始狀態 position指向陣列起始位置0,limit與capacity都是陣列長度位置
ByteBuffer.allocate(24); //當需要將10個位元組寫入channel通道時,就使用如下,position就會移動到10的陣列位置,limit和capacity不變。 byteBuffer.put(strings.getBytes());   //然後使用如下方法,這個時候作業系統就能夠從緩衝區裡面將這10個位元組傳送出去了。position重回到0,limit變為之前position位置即10,capacity不變。 byteBuffer.flip(); //然後客戶端write Buffer就傳送了資料 client.write(byteBuffer);   // ps:在下次寫資料之前呼叫一下clear(),Buffer索引迴歸起始狀態 // 使用mark(),可以將當前position的前一個位置記錄下來,當呼叫reset的時候position會恢復mark記錄下來的值 複製程式碼

比傳統檔案訪問方式更好的NIO檔案訪問方式 -- FileChannel.transferTo/transferFrom與FileChannel.map

FileChannel.transferTo/transferFrom:

1. 為什麼說比傳統的好,比如傳統的檔案訪問需要將檔案從磁碟中讀取資料到核心空間中,然後從核心空間讀取到使用者空間,在使用者空間進行一些自定義操作,再把操作後的資料讀入核心空間,存入磁碟。

2. 而transferTo/transferFrom只需要把資料從磁碟讀取到核心空間,然後就直接在核心空間進行操作,然後再寫入磁碟就行了。孰優孰劣,顯而易見。

##### FileChannel.map

1. 那麼map是怎麼操作的呢?它顯示將檔案按照一定大小對映到一塊記憶體區域中,當程式訪問時,直接操作這塊記憶體區域資料,但這種方式只適合於大檔案的只讀性操作。比如 MD5校驗。

AIO(asynchronous I/O) -- 非同步非阻塞IO

當需要對執行緒實現非同步呼叫的時候就可以使用AIO

最後總結一下它們的應用場景:

1. BIO方式適用於連線數目比較小且固定的架構,併發侷限於應用中。

2. NIO方式適用於連線數目多且連線比較短(輕操作)的架構,比如聊天伺服器,併發侷限於應用中。

3. AIO方式使用於連線數目多且連線比較長(重操作)的架構,比如相簿伺服器,充分呼叫OS參與併發操作。

參考書籍 -- 《深入分析Java Web技術內幕》