傳統的網絡服務器只支持阻塞模型,該模型下,針對每一個客戶端鏈接,服務器都必須建立一個線程來處理這個鏈接上的請求,服務器必須維持着這些線程直到線程中的處理工做結束。緩存
服務器上所能建立的線程數量是有限的,WHY?服務器
因此當鏈接到服務器上的客戶端的數量很大時,把服務器上所能建立的線程都佔據了時,服務器就沒法接受更多的鏈接了。這限制了服務器處理請求的伸縮性。網絡
存在這樣一個事實,就是雖然鏈接到服務器上的客戶端不少,但並不是全部客戶端都是持續活躍着的。它們佔據着阻塞式服務器的線程資源——即便它們處於非工做狀態。這些線程佔據了資源,卻不工做。多線程
這會形成什麼現象呢?
就是線程時間的碎片化——一個線程大部分時間是在等待IO操做的結果。併發
爲了讓服務器能接受更多客戶端的鏈接,非阻塞模型就出現了。異步
消滅碎片化時間,能夠提高服務器的併發處理能力。操作系統
如何消滅碎片化時間? 讓線程分工協做各司其職,是一個很好的手段。
原來的阻塞模型下,一個線程要幹全部的事情。分工協做機制下,一部分線程專門用於接受客戶端的鏈接、一部分專門用於獲取請求的數據、一部分專門執行計算工做、還有一部分線程專門用於響應客戶端。
接受客戶端鏈接的線程在接收到客戶端鏈接後,當即把鏈接交給後續工序的線程處理,而它本身則繼續接受下一個鏈接。如此類推,各個線程無須等待,不存在碎片化時間,全負荷工做。
這樣一來,總體上須要的較少的線程,就能夠完成之前須要較多線程才能達到的工做時間了。線程
在阻塞模型下,利用異步處理的方式對線程進行分工協做。接收請求的線程能夠滿負荷工做,但處理IO操做的線程仍然是阻塞着的,仍然存在線程工做不飽和的現象。進程
非阻塞模型下,IO操做再也不是阻塞的了,而是當即返回。這樣的話,處理IO操做的線程,能夠在空閒時對全部請求進行輪詢,以便判斷哪些IO操做已完成。好比判斷某個請求是否能夠進行「寫」操做,若是還不能夠,無須等待,繼續判斷下一個請求是否能夠進行「讀」操做,若是能夠則當即讀取數據,而後把數據轉交給專職計算的線程。這樣就讓線程工做不飽和現象消失了。內存
這是所謂的「同步非阻塞」。
這就要請出「IO複用」這尊大神了。
IO複用模型下,線程一次性從操做系統那兒得到一批能夠進行IO操做的請求,處理完畢後,再此得到新的一批。線程無須與操做系統交互屢次以便輪詢每一個請求的狀態,而是與操做系統交互一次便可得到批量信息。效率進一步提升啦。