通常的,對乙個檔案描述符指定的檔案或裝置, 有兩種工作方式: 阻塞 與非阻塞 。所謂阻塞方式的意思是指, 當試圖對該檔案描述符進行讀寫時, 如果當時沒有東西可讀,或者暫時不可寫, 程式就進入等待 狀態, 直到有東西可讀或者可寫為止。而對於非阻塞狀態, 如果沒有東西可讀, 或者不可寫, 讀寫函式馬上返回, 而不會等待 。一種常用做法是:每建立乙個socket連線時,同時建立乙個新執行緒對該socket進行單獨通訊(採用阻塞的方式通訊)。這種方式具有很高的響應速度,並且控制起來也很簡單,在連線數較少的時候非常有效,但是如果對每乙個連線都產生乙個執行緒的無疑是對系統資源的一種浪費,如果連線數較多將會出現資源不足的情況。
另一種較高效的做法是:伺服器端儲存乙個socket連線列表,然後對這個列表進行輪詢,如果發現某個socket埠上有資料可讀時(讀就緒),則呼叫該socket連線的相應讀操作;如果發現某個 socket埠上有資料可寫時(寫就緒),則呼叫該socket連線的相應寫操作;如果某個埠的socket連線已經中斷,則呼叫相應的析構方法關閉該埠。這樣能充分利用伺服器資源,效率得到了很大提高。
傳統的阻塞式io,每個連線必須要開乙個執行緒來處理,並且沒處理完執行緒不能退出。
非阻塞式io,由於基於反應器模式,用於事件多路分離和分派的體系結構模式,所以可以利用執行緒池來處理。事件來了就處理,處理完了就把執行緒歸還。而傳統阻塞方式不能使用執行緒池來處理,假設當前有10000個連線,非阻塞方式可能用1000個執行緒的執行緒池就搞定了,而傳統阻塞方式就需要開10000個來處理。如果連線數較多將會出現資源不足的情況。非阻塞的核心優勢就在這裡。
首先,我們來分析傳統阻塞式io的瓶頸在**。在連線數不多的情況下,傳統io編寫容易方便使用。但是隨著連線數的增多,問題傳統io就不行了。因為前面說過,傳統io處理每個連線都要消耗 乙個執行緒,而程式的效率當執行緒數不多時是隨著執行緒數的增加而增加,但是到一定的數量之後,是隨著執行緒數的增加而減少。這裡我們得出結論,傳統阻塞式io的瓶頸在於不能處理過多的連線。
然後,非阻塞式io的出現的目的就是為了解決這個瓶頸。而非阻塞式io是怎麼實現的呢?非阻塞io處理連線的執行緒數和連線數沒有聯絡,也就是說處理10000個連線非阻塞io不需要10000個執行緒,你可以用1000個也可以用2000個執行緒來處理。因為非阻塞io處理連線是非同步的。當某個連線傳送請求到伺服器,伺服器把這個連線請求當作乙個請求"事件",並把這個"事件"分配給相應的函式處理。我們可以把這個處理函式放到執行緒中去執行,執行完就把執行緒歸還。這樣乙個執行緒就可以非同步的處理多個事件。而阻塞式io的執行緒的大部分時間都浪費在等待請求上了。
阻塞IO與非阻塞IO
阻塞io,當前程序因不滿足一些條件,而被掛起,即阻塞,cpu改去服務其它程序,read乙個普通檔案,就馬上執行,read乙個滑鼠,可是滑鼠沒有動,於是就阻塞了,阻塞的好處,利於os效能的發揮,cpu發揮高,雖然個體的費了點時間,但是總的效率得到了提高,阻塞在多路io的時候,缺陷就出來了,比如2路io...
非阻塞IO與阻塞IO
非阻塞式呼叫的問題 kibuv提供了乙個執行緒池 阻塞於非阻塞對於被呼叫者,即系統層面,系統為程式提供了阻塞呼叫和非阻塞呼叫,同步和非同步是對於呼叫者,就是自己的程式,發七呼叫,沒有其他操作,只是等待結果這個過程就是同步,發起呼叫後會等待結果,繼續完成其他的工作,等有回掉再執行,這個過程就是非同步的...
阻塞與非阻塞I O
還記得上篇 我們講到的是linux中併發控制訪問的手段有哪些?原子 訊號量 自旋鎖 互斥體。這是為了保護臨界區的資源,是多個程序對共享資源的併發訪問的一種處理手段。但是,在驅動程式中,我們常常為了支援使用者空間對裝置的靈活訪問,引入了阻塞與非阻塞i o兩種不同模式。阻塞操作是指在執行裝置操作時若不能...