非同步程式設計:協作性多工處理
如何確保同時處理多個請求,我們可以使用執行緒或程序進行多工處理實現,但還有一個選擇 - 協作性多工處理。
這個選項是最困難的。在這裡我們說作業系統當然很酷,它有排程程式/計劃程式,它可以處理程序,執行緒,組織它們之間的切換,處理鎖等,但它仍然不知道應用程式是如何工作的,而這些工作原理應該是我們作為開發人員所知道的。
我們知道在CPU上會有短暫的時刻執行某些計算操作,但大多數時候我們都期望網絡I / O能更清楚何時在處理多個請求之間切換。
從作業系統的角度來看,協作式多工只是一個執行執行緒,在其中,應用程式在處理多個請求/命令之間切換。通常情況是:只要一些資料到達,就會讀取它們,解析請求,將資料傳送到資料庫,這是一個阻塞操作;而非堵塞操作時在等待來自資料庫的響應時,可以開始處理另一個請求,它被稱為“合作或協作”,因為所有任務/命令必須通過合作以使整個排程方案起作用。它們彼此交錯,但是有一個控制執行緒,稱為協作排程程式,其角色只是啟動程序並讓這些執行緒自動將控制權返回給它。
這比執行緒的多工處理更簡單,因為程式設計師總是知道當一個任務執行時,另一個任務不會執行,雖然在單處理器系統中,執行緒應用程式也將以交錯模式執行這種模型,但使用執行緒的程式設計師仍應考慮此方法的缺陷,以免應用程式在移動到多處理器系統時工作不正常。但是,即使在多處理器系統上,單執行緒非同步系統也總是以交錯方式執行。
編寫這樣的程式的困難在於,這種切換,維護上下文的過程,將每個任務組織為一系列間歇性執行的較小步驟,落在開發人員身上。另一方面,我們獲得了效率,因為沒有不必要的切換,例如,線上程和程序之間切換時切換處理器上下文沒有問題。
有兩種方法可以實現協作式多工處理 :回撥和綠色執行緒。
回撥
由於所有阻塞操作都會導致某個動作將在未來的某個時間發生,並且我們的執行執行緒應該在準備就緒時返回結果。因此,為了獲得結果,我們必須註冊回撥 - 當請求/操作成功時,它將執行一個回撥,或者如果它不成功,它將執行另一個回撥。回撥是一個明確的選項 - 開發人員應該以這樣的方式編寫程式,使他不知道何時將呼叫回撥函式。
這是最常用的選項,因為它是顯式的,並且得到了大多數現代語言的支援。
利弊:
- 與執行緒併發程式不同,沒有執行緒併發的問題;
- 執行緒/協同程式對程式設計師來說是不可見的;
- 回撥會吞掉異常;
- 回撥後的回撥變得混亂,難以除錯。
綠色執行緒
第二個選項是隱式的 ,當開發人員以這樣的方式編寫程式時,似乎不需要進行合作的多工處理。我們就像之前一樣做了一個阻塞操作,我們希望像只有一個程序或執行緒情況下獲得結果。但是有一個黑魔法“在幕後” : 框架或程式語言使阻塞操作實現非阻塞,並將控制轉移到其他一些執行執行緒,而不是轉移到OS執行緒上,是在一個邏輯執行緒(使用者 -級別執行緒)。它們由“普通”使用者級程序排程,而不是由核心排程,這個執行緒稱為綠色執行緒。
利弊:
- 是在應用程式級別而不是OS;
- 他們感覺像執行緒;
- 包括除CPU上下文切換之外的普通基於執行緒的程式設計的所有問題。
Reactor模式
在協作式多工處理中,總有一個任務處理核心負責所有I / O處理。設計模式 上稱為Reactor模式。Reactor介面說:“給我一堆你的Socket和你的回撥,當某個Socket準備好進行I / O時,我會呼叫你的回撥函式。”
Reactor提供了第二個介面,稱為定時器 - “在X毫秒內呼叫我,這是我需要你呼叫的回撥。”
這種東西在任何地方都是協作式的多工處理,無論是明確的還是隱含的。
“在引擎蓋下”Reactor非常簡單。它有一個按響應時間排序的計時器列表。它獲取給出它的Socket列表,並將它們傳送到輪詢準備機制中。可用性輪詢機制總是有一個引數: 它說明了如果沒有網路活動他將堵塞多長時間。阻塞時間表示最近的計時器的響應時間。因此,要麼存在某種網路活動,一些Socket將為I / O做好準備,或者我們將等待下一個定時器觸發,解鎖並將控制轉移到一個或另一個回撥,基本上是邏輯流程執行。
最好的方法
但實際上,這些選項都不是理想選擇。合併後的版本效果最好,因為協作式多工通常會帶來好處,特別是如果您的連線掛起很長時間。例如,Web Socket是一種長期連線。如果分配一個程序或一個執行緒來處理單個Web Socket,則會顯著地限制同時在一個後端伺服器上可以擁有的連線數。由於連線存在很長時間,因此保持多個同時連線非常重要,而每個連線的工作量很少。
沒有協作式多工處理的程式只能使用一個處理器核心。當然,您可以在同一臺機器上執行應用程式的多個例項(這並不總是方便且有其缺點),因此在每個程序內執行多個執行緒並使用reactor進行協同多工處理會很不錯。
這種組合一方面可以在我們的系統中使用所有可用的處理器核心,另一方面,它可以在每個核心中高效工作,而無需分配大量資源來處理每個單獨的連線。