通訊中的BIO與NIO
從BIO到NIO
BIO阻塞式的IO,NIO非阻塞式的IO。這裡從一個通訊的併發問題講起。
我們知道當併發量大的時候我們能夠採用的解決或者是擴充套件方式有兩種:橫向擴充套件(增大執行緒的數目),縱向擴充套件(使得每個執行緒得到良好的使用)。
在併發量大的時候我們可以啟用多個執行緒,比如說我們常用的手段就是執行緒池。但是如果執行緒阻塞每個執行緒還是得不到充分的利用。這時候我們就應該使用NIO來使得每個執行緒的利用更加的充分,這個操作屬於縱向擴充套件。
這裡就具體的列出BIO通訊的缺點,
①基於BIO的通訊,每來一個客戶端就會啟動一個執行緒這樣的話就會產生大量的執行緒。
同時由於大量的執行緒,會使得CPU來回切換的成本增高。
②由於阻塞,比如說read,write,accept,connect這些方法都會阻塞。所以單個執行緒的利用效率低。
③當一個執行緒被佔用但是它本身並沒有工作,這樣的話這個執行緒就會出現置空期,這時CPU就只是無意義的空轉。
NIO與BIO各有優缺點,NIO可能不擅長處理長請求(因為它可能受到一些資源排程器的控制被來回切換)。所以一般在處理長請求比如說下載大的檔案使用BIO更加合適。
多路選擇的引出
多路選擇就器就像是一個資源排程器一樣,在他的上面註冊了很多的通訊的執行緒。它的作用就是在一些執行緒空閒的時候將這個執行緒空出來供其他客戶端使用。而當監聽到一個客戶發起請求或者是傳輸動作的時候就會個當前的操作分配執行緒。這樣的話就能夠靈活的使用有限的執行緒打出最大的傷害。
FileChannel與ZeroCopy
我們平常看起來的遠端檔案傳輸的背後起始隱藏著大量的拷貝操作如下圖所示:
①首先從硬碟上拷貝到ReadBuffer中,這裡的ReadBuffer是核心態(一種許可權較高的狀態,可以享有各種底層許可權)。
②然後拷貝到ApplicationBuffer(這裡是使用者態,使用者態就是將核心態的功能刪減了很多然供使用者來呼叫)。
③將ApplicationBuffer操作之後(事實上這裡並不去操作),然後拷貝到SocketBuffer中。
④最後將SocketBuffer中的內容拷貝到NIC(網絡卡)的快取中。
ZeroCopy的基本原理就是將中間的兩步複製操作刪除。如下圖所示:
這樣的話也就提升了效率。Java中Channel類就是基於ZeroCopy的。
transferFrom(ReadableByteChannel src, long position, long count)