轉自:http://wenku.baidu.com/link?url=V-TghOmERC0eq0aoXEyhpTw3W5OlqbItwTJE_csI29ysi9vKkCG1lDxq0wWdpImvg3qFf1BKUrDEPUz-4uCbiROduS0EswpvmBvuzVfbtuO服務器
NIO 設計背後的基石:反應器模式,用於事件多路分離和分派的體系結構模式。 反應器(Reactor):用於事件多路分離和分派的體系結構模式
一般的,對一個文件描述符指定的文件或設備, 有兩種工做方式: 阻塞與非阻塞 。所謂阻塞方式的意思是指,當試圖對該文件描述符進行讀寫時,若是當時沒有東西可讀,或者暫時不可寫,程序就進入等待狀態,直到有東西可讀或者可寫爲止。而對於非阻塞狀態,若是沒有東西可讀,或者不可寫,讀寫函數立刻返回,而不會等待。
一種經常使用作法是:每創建一個Socket鏈接時,同時建立一個新線程對該Socket進行單獨通訊(採用阻塞的方式通訊)。這種方式具備很高的響應速度,而且控制起來也很簡單,在鏈接數較少的時候很是有效,可是若是對每個鏈接都產生一個線程的無疑是對系統資源的一種浪費,若是鏈接數較多將會出現資源不足的狀況。
另外一種較高效的作法是:服務器端保存一個Socket鏈接列表,而後對這個列表進行輪詢,若是發現某個Socket端口上有數據可讀時(讀就緒),則調用該socket鏈接的相應讀操做;若是發現某個 Socket端口上有數據可寫時(寫就緒),則調用該socket鏈接的相應寫操做;若是某個端口的Socket鏈接已經中斷,則調用相應的析構方法關閉該端口。這樣能充分利用服務器資源,效率獲得了很大提升。
傳統的阻塞式IO,每一個鏈接必需要開一個線程來處理,而且沒處理完線程不能退出。
非阻塞式IO,因爲基於反應器模式,用於事件多路分離和分派的體系結構模式,因此能夠利用線程池來處理。事件來了就處理,處理完了就把線程歸還。而傳統阻塞方式不能使用線程池來處理,假設當前有10000個鏈接,非阻塞方式可能用1000個線程的線程池就搞定了,而傳統阻塞方式就須要開10000個來處理。若是鏈接數較多將會出現資源不足的狀況。非阻塞的核心優點就在這裏。
爲何會這樣,下面就對他們作進一步細緻具體的分析:
首先,咱們來分析傳統阻塞式IO的瓶頸在哪裏。在鏈接數很少的狀況下,傳統IO編寫容易方便使用。可是隨着鏈接數的增多,問題傳統IO就不行了。由於前面說過,傳統IO處理每一個鏈接都要消耗一個線程,而程序的效率當線程數很少時是隨着線程數的增長而增長,可是到必定的數量以後,是隨着線程數的增長而減小。這裏咱們得出結論,傳統阻塞式IO的瓶頸在於不能處理過多的鏈接。
而後,非阻塞式IO的出現的目的就是爲了解決這個瓶頸。而非阻塞式IO是怎麼實現的呢?非阻塞IO處理鏈接的線程數和鏈接數沒有聯繫,也就是說處理10000個鏈接非阻塞IO不須要10000個線程,你能夠用1000個也能夠用2000個線程來處理。由於非阻塞IO處理鏈接是異步的。當某個鏈接發送請求到服務器,服務器把這個鏈接請求看成一個請求"事件",並把這個"事件"分配給相應的函數處理。咱們能夠把這個處理函數放到線程中去執行,執行完就把線程歸還。這樣一個線程就能夠異步的處理多個事件。而阻塞式IO的線程的大部分時間都浪費在等待請求上了。異步