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

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

傳統的網絡服務器只支持阻塞模型,該模型下,針對每個客戶端連接,服務器都必須創建一個線程來處理這個連接上的請求,服務器必須維持着這些線程直到線程中的處理工作結束。

服務器上所能創建的線程數量是有限的,WHY?

  • 進程上下文切換是耗時的過程
  • 創建的進程本身佔用資源,比如每個進程或線程佔用一定容量的內存
  • 等待數據準備和內核緩存複製,導致IO阻塞,佔用着線程

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

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

存在這樣一個事實,就是雖然連接到服務器上的客戶端很多,但並非所有客戶端都是持續活躍着的。它們佔據着阻塞式服務器的線程資源——即使它們處於非工作狀態。爲了讓服務器能接受更多客戶端的連接,非阻塞模型就出現了。

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

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

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

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

阻塞模型下的實現方式

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

非阻塞模型徹底消滅線程工作不飽和

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

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

輪詢的耗時如何消滅?

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

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章