從時間碎片角度理解阻塞IO模型及非阻塞模型

資料價值發表於2018-12-01

阻塞模型限制了伺服器的併發處理能力(伸縮性或同時處理的客戶端連線數)

傳統的網路伺服器只支援阻塞模型,該模型下,針對每個客戶端連線,伺服器都必須建立一個執行緒來處理這個連線上的請求,伺服器必須維持著這些執行緒直到執行緒中的處理工作結束。

伺服器上所能建立的執行緒數量是有限的,WHY?

  • 程式上下文切換是耗時的過程
  • 建立的程式本身佔用資源,比如每個程式或執行緒佔用一定容量的記憶體
  • 等待資料準備和核心快取複製,導致IO阻塞,佔用著執行緒

所以當連線到伺服器上的客戶端的數量很大時,把伺服器上所能建立的執行緒都佔據了時,伺服器就無法接受更多的連線了。這限制了伺服器處理請求的伸縮性。

並非所有客戶端都是持續活躍的

存在這樣一個事實,就是雖然連線到伺服器上的客戶端很多,但並非所有客戶端都是持續活躍著的。它們佔據著阻塞式伺服器的執行緒資源——即使它們處於非工作狀態。這些執行緒佔據了資源,卻不工作。

這會造成什麼現象呢?
就是執行緒時間的碎片化——一個執行緒大部分時間是在等待IO操作的結果。

為了讓伺服器能接受更多客戶端的連線,非阻塞模型就出現了。

如何提升伺服器的併發處理能力?

消滅碎片化時間,可以提升伺服器的併發處理能力。

如何消滅碎片化時間? 讓執行緒分工協作各司其職,是一個很好的手段。
原來的阻塞模型下,一個執行緒要幹所有的事情。分工協作機制下,一部分執行緒專門用於接受客戶端的連線、一部分專門用於獲取請求的資料、一部分專門執行計算工作、還有一部分執行緒專門用於響應客戶端。
接受客戶端連線的執行緒在接收到客戶端連線後,立即把連線交給後續工序的執行緒處理,而它自己則繼續接受下一個連線。如此類推,各個執行緒無須等待,不存在碎片化時間,全負荷工作。
這樣一來,整體上需要的較少的執行緒,就可以完成以前需要較多執行緒才能達到的工作時間了。

阻塞模型下的實現方式

在阻塞模型下,利用非同步處理的方式對執行緒進行分工協作。接收請求的執行緒可以滿負荷工作,但處理IO操作的執行緒仍然是阻塞著的,仍然存線上程工作不飽和的現象。

非阻塞模型徹底消滅執行緒工作不飽和

非阻塞模型下,IO操作不再是阻塞的了,而是立即返回。這樣的話,處理IO操作的執行緒,可以在空閒時對所有請求進行輪詢,以便判斷哪些IO操作已完成。比如判斷某個請求是否可以進行“寫”操作,如果還不可以,無須等待,繼續判斷下一個請求是否可以進行“讀”操作,如果可以則立即讀取資料,然後把資料轉交給專職計算的執行緒。這樣就讓執行緒工作不飽和現象消失了。

這是所謂的“同步非阻塞”。

輪詢的耗時如何消滅?

這就要請出“IO複用”這尊大神了。

IO複用模型下,執行緒一次性從作業系統那兒獲得一批可以進行IO操作的請求,處理完畢後,再此獲得新的一批。執行緒無須與作業系統互動多次以便輪詢每個請求的狀態,而是與作業系統互動一次即可獲得批量資訊。效率進一步提高啦。


相關文章