1. 程式人生 > >BIO、NIO、AIO 區別和應用場景

BIO、NIO、AIO 區別和應用場景

前邊簡單介紹過IO的基本情況  Java IO流

簡單回顧

對於IO我們應該非常熟悉了,IO不僅僅針對檔案的操作,網路程式設計socket的通訊,就是IO操作。

輸入、輸出流(InputStream、OutputStream)用於讀取或寫入位元組,如操作圖片、視訊等。

Reader和Writer 則用於操作字元,增加了字元編碼功能。本質上計算機操作都是位元組,不管是網路或者檔案,Reader和Writer等於構建了應用邏輯和原始資料的另一層通道。

BufferedOutputStream、BufferedInputStream等帶有緩衝區的實現,可以避免頻繁的磁碟操作,通過設計緩衝區將批量資料進行一次操作。

NIO

 能解決什麼問題?

      為什麼要有NIO,NIO是什麼?

首先看一下BIO,如果有一臺伺服器,能承受簡單的客戶端請求,那麼使用io和net中的同步、阻塞式API應該是可以實現了。但是為了一個使用者的請求而單獨啟動一個執行緒,開銷應該不小吧。java語言對執行緒的實現是比較重量的,啟動或銷燬執行緒,都會有明顯開銷,每個執行緒都有單獨的執行緒棧佔用明顯的記憶體。引入執行緒池,就能很大程度的避免不必要的開銷。

這種情況適合連線數並不多,只有最多幾百個連線的普通應用,能比較好的進行工作,但如果連線數量劇增,這種實現方式就無法很好的工作了,對於併發量要求較高的企業,這種方案,肯定是不可取的。

NIO採用的是一種多路複用的機制,利用單執行緒輪詢事件,高效定位就緒的Channel來決定做什麼,只是Select階段是阻塞式的,能有效避免大量連線數時,頻繁執行緒的切換帶來的效能或各種問題。

上圖隨便畫的,只是方便理解,並不能作為實現的具體的參考。

首先,Requester方通過Selector.open()建立了一個Selector準備好了排程角色。

建立了SocketChannel(ServerSocketChannel) 並註冊到Selector中,通過設定key(SelectionKey)告訴排程者所應該關注的連線請求。

阻塞,Selector阻塞在select操作中,如果發現有Channel發生連線請求,就會喚醒處理請求。

NIO同步非阻塞式IO

      對比BIO的同步阻塞IO操作,實際上NIO是同步非阻塞IO,一個執行緒在同步的進行輪詢檢查,Selector不斷輪詢註冊在其上的Channel,某個Channel上面發生讀寫連線請求,這個Channel就處於就緒狀態,被Selector輪詢出來,然後通過SelectionKey可以獲取就緒Channel的集合,進行後續的I/O操作。

       同步和非同步說的是訊息的通知機制,這個執行緒仍然要定時的讀取stream,判斷資料有沒有準備好,client採用迴圈的方式去讀取(執行緒自己去抓去資訊),CPU被浪費。

     非阻塞:體現在,這個執行緒可以去幹別的,不需要一直在這等著。Selector可以同時輪詢多個Channel,因為JDK使用了epoll()代替傳統的select實現,沒有最大連線控制代碼限制。所以只需要一個執行緒負責Selector的輪詢,就可以接入成千上萬的客戶端。

AIO

是在NIO的基礎上引入非同步通道的概念,實現非同步非阻塞式的IO處理。如下圖(網路截圖):

        AIO不需要通過多路複用器對註冊的通道進行輪詢操作即可實現非同步讀寫。什麼意思呢?NIO採用輪詢的方式,一直在輪詢的詢問stream中資料是否準備就緒,如果準備就緒發起處理。但是AIO就不需要了,AIO框架在windows下使用windows IOCP技術,在Linux下使用epoll多路複用IO技術模擬非同步IO, 即:應用程式向作業系統註冊IO監聽,然後繼續做自己的事情。作業系統發生IO事件,並且準備好資料後,在主動通知應用程式,觸發相應的函式(這就是一種以訂閱者模式進行的改造)。由於應用程式不是“輪詢”方式而是訂閱-通知方式,所以不再需要selector輪詢,由channel通道直接到作業系統註冊監聽。

NIO(AIO)中幾個概念

緩衝區 Buffer

NIO基於塊進行資料處理,在NIO中所有資料的讀取都是通過緩衝Buffer進行處理。

     具體的快取區有這些:ByteBuffe、CharBuffer、 ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。他們實現了相同的介面:Buffer。

通道 Channel

     對資料的讀取和寫入要通過Channel通道。通道不同於流的地方就是通道是雙向的,用於讀、寫和同時讀寫操作。底層的作業系統的通道一般都是全雙工的,全雙工的Channel比流能更好的對映底層作業系統的API。

多路複用器 Selector

Selector提供選擇已經就緒的任務的能力:

      Selector輪詢註冊在其上的Channel,如果某個Channel發生讀寫請求並且Channel就處於就緒狀態,會被Selector輪詢出來,然後通過SelectionKey可以獲取就緒Channel的集合,進行後續的I/O操作。(同步)

      一個Selector可以同時輪詢多個Channel,因為JDK使用了epoll()代替傳統的select實現,所以沒有最大連線控制代碼1024/2048的限制。所以,只需要一個執行緒負責Selector的輪詢,就可以接入成千上萬的客戶端。(非阻塞)

NIO和AIO

NIO:會等資料準備好後,再交由應用進行處理,資料的讀取/寫入過程依然在應用執行緒中完成,只是將等待的時間剝離到單獨的執行緒中去,節省了資料準備時間,因為多路複用機制,Selector會得到複用,對於那些讀寫過程時間長的,NIO就不太適合。

AIO:讀完(核心記憶體拷貝到使用者記憶體)了系統再通知應用,使用回撥函式,進行業務處理,AIO能夠勝任那些重量級,讀寫過程長的任務。