NIO和傳統IO之我見

傳統的socket IO中,須要爲每一個鏈接建立一個線程,當併發的鏈接數量很是巨大時,線程所佔用的棧內存和CPU線程切換的開銷將很是巨大。使用NIO,再也不須要爲每一個線程建立單獨的線程,能夠用一個含有限數量線程的線程池,甚至一個線程來爲任意數量的鏈接服務。因爲線程數量小於鏈接數量,因此每一個線程進行IO操做時就不能阻塞,若是阻塞的話,有些鏈接就得不處處理,NIO提供了這種非阻塞的能力。java

小量的線程如何同時爲大量鏈接服務呢,答案就是就緒選擇。這就比如到餐廳吃飯,每來一桌客人,都有一個服務員專門爲你服務,從你到餐廳到結賬走人,這樣方式的好處是服務質量好,一對一的服務,VIP啊,但是缺點也很明顯,成本高,若是餐廳生意好,同時來100桌客人,就須要100個服務員,那老闆發工資的時候得心痛死了,這就是傳統的一個鏈接一個線程的方式。git

老闆是什麼人啊,精着呢。這老闆就得捉摸怎麼能用10個服務員同時爲100桌客人服務呢,老闆就發現,服務員在爲客人服務的過程當中並非一直都忙着,客人點完菜,上完菜,吃着的這段時間,服務員就閒下來了,但是這個服務員仍是被這桌客人佔用着,不能爲別的客人服務,用華爲領導的話說,就是工做不飽滿。那怎麼把這段閒着的時間利用起來呢。這餐廳老闆就想了一個辦法,讓一個服務員(前臺)專門負責收集客人的需求,登記下來,好比有客人進來了、客人點菜了,客人要結賬了,都先記錄下來按順序排好。每一個服務員到這裏領一個需求,好比點菜,就拿着菜單幫客人點菜去了。點好菜之後,服務員立刻回來,領取下一個需求,繼續爲別人客人服務去了。這種方式服務質量就不如一對一的服務了,當客人數據不少的時候可能須要等待。但好處也很明顯,因爲在客人正吃飯着的時候服務員不用閒着了,服務員這個時間內能夠爲其餘客人服務了,原來10個服務員最多同時爲10桌客人服務,如今可能爲50桌,60客人服務了。github

這種服務方式跟傳統的區別有兩個: 一、增長了一個角色,要有一個專門負責收集客人需求的人。NIO裏對應的就是Selector。 二、由阻塞服務方式改成非阻塞服務了,客人吃着的時候服務員不用一直侯在客人旁邊了。傳統的IO操做,好比read(),當沒有數據可讀的時候,線程一直阻塞被佔用,直到數據到來。NIO中沒有數據可讀時,read()會當即返回0,線程不會阻塞。數據庫

NIO中,客戶端建立一個鏈接後,先要將鏈接註冊到Selector,至關於客人進入餐廳後,告訴前臺你要用餐,前臺會告訴你你的桌號是幾號,而後你就可能到那張桌子坐下了,SelectionKey就是桌號。當某一桌須要服務時,前臺就記錄哪一桌須要什麼服務,好比1號桌要點菜,2號桌要結賬,服務員從前臺取一條記錄,根據記錄提供服務,完了再來取下一條。這樣服務的時間就被最有效的利用起來了。 --------上面描述引用自http://blog.csdn.net/zhouhl_cn/article/details/6568119 在實際的應用中,NIO的使用也是遍及java的框架中,我這邊主要對Netty的NIO的應用進行簡要的介紹:源碼地址https://github.com/netty/netty, 網絡模型網絡

在上圖的網絡模型中,去掉線程池的形式,就是 是Netty NIO的默認模式。在實現上,Netty中的Boss類充當mainReactor,NioWorker類充當subReactor(默認 NioWorker的個數是Runtime.getRuntime().availableProcessors())。在處理新來的請求 時,NioWorker讀完已收到的數據到ChannelBuffer中,以後觸發ChannelPipeline中的ChannelHandler流。併發

Netty是事件驅動的,能夠經過ChannelHandler鏈來控制執行流向。由於ChannelHandler鏈的執行過程是在 subReactor中同步的,因此若是業務處理handler耗時長,將嚴重影響可支持的併發數。這種模型適合於像Memcache這樣的應用場景,但 對須要操做數據庫或者和其餘模塊阻塞交互的系統就不是很合適。Netty的可擴展性很是好,而像ChannelHandler線程池化的須要,能夠經過在 ChannelPipeline中添加Netty內置的ChannelHandler實現類–ExecutionHandler實現,對使用者來講只是 添加一行代碼而已。對於ExecutionHandler須要的線程池模型,Netty提供了兩種可 選:1) MemoryAwareThreadPoolExecutor 可控制Executor中待處理任務的上限(超過上限時,後續進來的任務將被阻 塞),並可控制單個Channel待處理任務的上限;2) OrderedMemoryAwareThreadPoolExecutor 是 MemoryAwareThreadPoolExecutor 的子類,它還能夠保證同一Channel中處理的事件流的順序性,這主要是控制事件在異步處 理模式下可能出現的錯誤的事件順序,但它並不保證同一Channel中的事件都在一個線程中執行(一般也不必)。通常來 說,OrderedMemoryAwareThreadPoolExecutor 是個很不錯的選擇,固然,若是有須要,也能夠DIY一個。框架

相關文章
相關標籤/搜索