詳解BIO與NIO的區別

1、 Reactor and Proactor數據庫

IO讀寫時,多路複用機制都會依賴對一個事件多路分離器,負責把源事件的IO 事件分離出來,分別到相應的read/write事件分離器。涉及到事件分離器的兩種模式分別就是 Reactor和Proactor,Reactor是基於同步IO的,Proactor是基於異步IO的。緩存

在Reactor模式中,事件分離者等待某個事件或者可應用或個操做的狀態發生(好比文件描述符可讀寫,或者是socket可讀寫),事件分離者就把這個事件傳給事先註冊的事件處理函數或者回調函數,由後者來作實際的讀寫操做。網絡

在Proactor模式中,事件處理者(或者代由事件分離者發起)直接發起一個異步讀寫操做(至關於請求),而實際的工做是由操做系統來完成的。發起時,須要提供的參數包括用於存放讀到數據的緩存區,讀的數據大小,或者用於存放外發數據的緩存區,以及這個請求完後的回調函數等信息。事件分離者得知了這個請求,它默默等待這個請求的完成,而後轉發完成事件給相應的事件處理者或者回調。舉例來講,在Windows上事件處理者投遞了一個異步IO操做(稱有 overlapped的技術),事件分離者等IOCompletion事件完成. 這種異步模式的典型實現是基於操做系統底層異步API的,因此咱們可稱之爲「系統級別」的或者「真正意義上」的異步,由於具體的讀寫是由操做系統代勞的。app

舉個例子,將有助於理解Reactor與Proactor兩者的差別,以讀操做爲例(類操做相似)。異步

在Reactor中實現讀:socket

- 註冊讀就緒事件和相應的事件處理器函數

- 事件分離器等待事件spa

- 事件到來,激活分離器,分離器調用事件對應的處理器。操作系統

- 事件處理器完成實際的讀操做,處理讀到的數據,註冊新的事件,而後返還控制權。線程

與以下Proactor(真異步)中的讀過程比較:

- 處理器發起異步讀操做(注意:操做系統必須支持異步IO)。在這種狀況下,處理器無視IO就緒事件,它關注的是完成事件。

- 事件分離器等待操做完成事件

- 在分離器等待過程當中,操做系統利用並行的內核線程執行實際的讀操做,並將結果數據存入用戶自定義緩衝區,最後通知事件分離器讀操做完成。

- 事件分離器呼喚處理器。

- 事件處理器處理用戶自定義緩衝區中的數據,而後啓動一個新的異步操做,並將控制權返回事件分離器。

能夠看出,兩個模式的相同點,都是對某個IO事件的事件通知(即告訴某個模塊,這個IO操做能夠進行或已經完成)。在結構

上,二者也有相同點:demultiplexor負責提交IO操做(異步)、查詢設備是否可操做(同步),而後當條件知足時,就回調handler;

不一樣點在於,異步狀況下(Proactor),當回調handler時,表示IO操做已經完成;同步狀況下(Reactor),回調handler時,表示

IO設備能夠進行某個操做(can read or can write),handler這個時候開始提交操做。

2、BIO、NIO、AIO

NIO一般採用Reactor模式,AIO一般採用Proactor模式。AIO簡化了程序的編寫,stream的讀取和寫入都有OS來完成,不須要像NIO那樣子遍歷Selector。Windows基於IOCP實現AIO,Linux只有eppoll模擬實現了AIO。

Java7以前的JDK只支持NIO和BIO,從7開始支持AIO。

4種通訊方式:TCP/IP+BIO, TCP/IP+NIO, UDP/IP+BIO, UDP/IP+NIO。

TCP/IP+BIO、

Socket和ServerSocket實現,ServerSocket實現Server端端口監聽,Socket用於創建網絡IO鏈接。

不適用於處理多個請求 1.生成Socket會消耗過多的本地資源。2. Socket鏈接的創建通常比較慢。

BIO狀況下,能支持的鏈接數有限,通常都採起accept獲取Socket之後採用一個thread來處理,one connection one thread。不管鏈接是否有真正數據請求,都須要獨佔一個thread。

能夠經過設立Socket池來必定程度上解決問題,可是使用池須要注意的問題是:1. 競爭等待比較多。 2. 須要控制好超時時間。

TCP/IP+NIO

使用Channel(SocketChannel和ServerSocketChannel)和Selector。

Server端一般由一個thread來監聽connect事件,另外多個thread來監聽讀寫事件。這樣作的好處是這些鏈接只有在真是請求的時候纔會建立thread來處理,one request one thread。這種方式在server端須要支持大量鏈接但這些鏈接同時發送請求的峯值不會不少的時候十分有效。

UDP/IP+BIO

DatagramSocket和DatagramPacket。DatagramSocket負責監聽端口以及讀寫數據,DatagramPacket做爲數據流對象進行傳輸。

UDP/IP是無鏈接的,沒法進行雙向通訊,除非雙方都成爲UDP Server。

UDP/IP+NIO

經過DatagramChannel和ByteBuffer實現。DatagramChannel負責端口監聽及讀寫。ByteBuffer負責數據流傳輸。

若是要將消息發送到多臺機器,若是爲每一個目標機器都創建一個鏈接的話,會有很大的網絡流量壓力。這時候可使用基於UDP/IP的Multicast協議傳輸,Java中能夠經過MulticastSocket和DatagramPacket來實現。

Multicast通常多用於多臺機器的狀態同步,好比JGroups。SRM, URGCP都是Multicast的實現方式。eBay就採用SRM來實現將數據從主數據庫同步到各個搜索節點機器。


本文出自 「陳硯羲」 博客,謝絕轉載!

相關文章
相關標籤/搜索