1. 程式人生 > >Reactor 模型(一)基本並發編程模型

Reactor 模型(一)基本並發編程模型

blog 操作 維護 .com 提交 就是 tps 內容 介紹

Reactor 模型(一)基本並發編程模型

Netty 系列目錄 (https://www.cnblogs.com/binarylei/p/10117436.html)

在講解 Reactor 線程模型之前,我們需要先對基本並發編程模型:串行工作模型、並發工作模型進行講解。

串行工作者模型和並行工作者模型關註的是將任務劃分為 2 個階段:一是任務的接受階段;二是任務的處理階段。而 Reactor 線程模型關註的是上述第二個階段:任務在處理的過程中,繼續劃分為多個步驟進行處理。

一、串行模型

我們以一個典型的任務處理流程,來說明為什麽要將任務的接受流程與處理流程劃分開來

技術分享圖片

在這個例子中,一個 Worker 線程來處理用戶提交的任務,任務的處理步驟粗略的分為:接受任務和處理任務兩個階段。當 Worker 接受到一個任務之後,就立刻進行處理,也就是說任務接受和任務處理是在同一個 Worker 線程中進行的,沒有進行區分。這樣做存在一個很大的問題是,必須要等待某個 Task 處理完成之後,才能接受處理下一個 Task。

而通常情況下,任務的處理過程會比任務的接受流程慢得多。例如在處理任務的時候,我們可能會需要訪問遠程數據庫,這屬於一種網絡 IO。通常情況下 IO 操作是比較耗時的,這直接影響了下一個任務的接受,而且通常在 IO 操作的時候,CPU 是比較空閑的,白白浪費了資源。

因此我們可以考慮將任務的接受與處理分為兩個線程進行處理,一個只負責接受任務,一個只負責處理任務。

這就演化出了第一個線程模型:串行工作者模型。如下所示:

技術分享圖片

在這種情況下,接受任務的線程稱之為 Accept Thread,其將接受到的任務放到一個任務隊列中,因此能立即返回接受下一個任務。而 Worker 線程不斷的從這個隊列中取出任務進行異步執行。

目前這種情況存在一個很大的問題,在於任務處理的太慢,導致隊列裏積壓的任務數量越來愈大,任務不能得到及時的執行。所以我們可以用多個 Worker Thread 來處理任務。這就是串行工作者模型的並發版本-並行工作者模型。

二、並行模型

在並行工作者模型中,有一個 Accpet Thread,多個 Worker Thread,因為 Worker Thread 的功能都相同,所以我們通常會將其劃分到一個組中(Worker Thread Group)。

在具體實現上,並行工作者線程模型有兩種設計方式,以下分別進行介紹。

2.1 基於公共任務隊列

並行工作者線程模型設計方式一:基於公共任務隊列

accept Thread 將接受到的任務放到任務隊列中,Worker Thread group 中的多個 Worker Thread 並行的從公共的隊列中拉取任務進行處理。

技術分享圖片

熟悉java線程池 的用戶可能已經發現,可以用ThreadPoolExecutor 來實現右半部分的功能,因為ThreadPoolExecutor 就是多個線程從一個公共的任務隊列中拉取任務進行執行。通過在main線程中接受任務,將任務提交到線程池中,即可以完成上述線程模型。

2.2 每個 Worker Thread 維護自己的任務隊列

在第一種方式中,由於多個Worker線程同時從一個公共的任務隊列中拉取任務進行處理,因此必須要進行加鎖,因而影響了效率。因此又有了下面一種設計方式:Reactor Thread直接將任務轉發給各個 Worker Thread,每個 Worker Thread 內部維護一個隊列來處理,如下圖

技術分享圖片

這種方式的設計,避免的鎖競爭,因為每個 Worker Thread 都從各自的隊列中取出任務進行執行。實際上,Netty 的實現中,就是為每個 Worker Thread 維護了一個隊列。

需要註意的是:由於現在是 Accpet Thread 直接給過個 Worker Thread 轉發任務,任務分配的平均的責任就落到了 Reactor Thread 的身上。


每天用心記錄一點點。內容也許不重要,但習慣很重要!

Reactor 模型(一)基本並發編程模型