一個故事講清楚NIO 一個故事講清楚NIO

轉載請引用:一個故事講清楚NIOhtml

  假設某銀行只有10個職員。該銀行的業務流程分爲如下4個步驟:web

1) 顧客填申請表(5分鐘);api

2) 職員審覈(1分鐘);網絡

3) 職員叫保安去金庫取錢(3分鐘);eclipse

4) 職員打印票據,並將錢和票據返回給顧客(1分鐘)。異步

  咱們看看銀行不一樣的工做方式對其工做效率到底有何影響。socket

1 BIO方式

  每來一個顧客,立刻由一位職員來接待處理,而且這個職員須要負責以上4個完整流程。當超過10個顧客時,剩餘的顧客須要排隊等候。post

  咱們算算這個銀行一個小時到底能處理多少顧客?一個職員處理一個顧客須要10分鐘(5+1+3+1)時間,一個小時(60分鐘)能處理6個顧客,一共10個職員,那就是隻能處理60個顧客。url

  能夠看到銀行職員的工做狀態並不飽和,好比在第1步,實際上是處於等待中。spa

  這種工做其實就是BIO,每次來一個請求(顧客),就分配到線程池中由一個線程(職員)處理,若是超出了線程池的最大上限(10個),就扔到隊列等待 。

2 NIO方式

  如何提升銀行的吞吐量呢?

  思路:分而治之,將任務拆分開來,由專門的人負責專門的任務。

  具體來說,銀行專門指派一名職員A,A的工做就是每當有顧客到銀行,他就遞上表格讓顧客填寫,每當有顧客填好表後,A就將其隨機指派給剩餘的9名職員完成後續步驟。

  咱們計算下這種工做方式下銀行一個小時到底能處理多少顧客?

  假設顧客很是多,職員A的工做處於飽和中,他不斷的將填好表的顧客帶到櫃檯處理,櫃檯一個職員5分鐘能處理完一個顧客,一個小時9名職員能處理:9*(60/5)=108。

  可見工做方式的轉變能帶來效率的極大提高。

      這種工做方式其實就NIO的思路。下圖是很是經典的NIO說明圖,mainReactor線程負責監聽server socket,accept新鏈接,並將創建的socket分派給subReactor;subReactor能夠是一個線程,也能夠是線程池(通常能夠設置爲CPU核數),負責多路分離已鏈接的socket,讀寫網絡數據,這裏的讀寫網絡數據可類比顧客填表這一耗時動做,對具體的業務處理功能,其扔給worker線程池完成。

  能夠看到典型NIO有三類線程,分別是mainReactor線程、subReactor線程、work線程。不一樣的線程幹專業的事情,最終每一個線程都沒空着,系統的吞吐量天然就上去了。

        

 

3 異步方式

  第二種工做方式有沒有什麼能夠提升的地方呢?

  仔細查看可發現第3步驟這3分鐘櫃檯職員是在等待中度過的,那怎麼能讓櫃檯職員保持滿負荷呢?

  仍是分而治之的思路,指派1個職員B來專門負責第3步驟。每當櫃檯員工完成第2步時,就通知職員B來負責與保安溝通取錢。這時候櫃檯員工能夠繼續處理下一個顧客。當職員B拿到錢以後,他會怎麼辦呢?他會通知顧客錢已經到櫃檯了,讓顧客從新排隊處理,當櫃檯職員再次服務該顧客時,發現該顧客前3步已經完成,直接執行第4步便可。

  咱們能夠算算經過這種方法,銀行的吞吐量能提升到多少。

  假設職員B的工做很是飽和,櫃檯一個職員如今2分鐘能處理完一個顧客,一個小時8名職員能處理:8*(60/2)=240。

  在當今web服務中,常常須要經過RPC或者Http等方式調用第三方服務,這裏對應的就是第3步,若是這步耗時較長,經過異步方式將能極大下降資源使用率。

  jetty Continuations 就實現了上述異步方式,有興趣的同窗能夠去嘗試下(http://wiki.eclipse.org/Jetty/Feature/Continuations)。

  NIO+異步的方式能讓少許的線程(資源)作大量的事情,這適用於不少應用場景,好比代理服務、api服務、長鏈接服務等等,這些應用若是用同步方式將耗費大量機器資源。儘管NIO+異步能提升系統吞吐量,但其並不能讓一個請求的等待時間降低,相反可能會增長等待時間。

 4 小結

  總結就一句:「分而治之,將任務拆分開來,由專門的人負責專門的任務」,這不只在計算機領域生效,在整個社會領域都生效。

相關文章
相關標籤/搜索