遇到一個多線程任務優化的問題,現在解決了,分享如下。
假設有四個任務:
任務1:登陸驗證(CheckUser)
任務2:驗證成功后從Web服務獲取數據(GetDataFromWeb)
任務3:驗證成功后從數據庫獲取數據(GetDatFromDb)
任務4:使用2、3的數據執行一個方法 (StartProcess)
一個比較笨的方法(本人最開始的方法,記為方法1)是直接開啟一個線程,按照順序依次執行四個任務:
但是仔細分析需求我們會發現,任務2和任務3并沒有先后區別,事實上兩者并無關聯,只不過任務4的執行需要任務2和3都已完成作為條件,所以我們可以再開兩個線程用于執行任務2和任務3,當兩者都執行完畢之后,執行任務4。
在這里使用了兩個全局變量用于表示任務2和任務3的狀態。用三個線程分別執行任務2、3、4,其中任務4一直在循環監聽全局變量的狀態,確保在2、3都執行完畢后才執行。
這記為方法2:
以上代碼基本上已經可以達到預期目標了,但是由于借助了兩個全局變量,盡管在這里不會涉及到同步沖突的問題,但總覺得很不放心,而且當我們需要做擴展的時候,比方說在執行任務4之前,我們還需要加載文件內的數據(GetDataFromFile),那我們必須再添加一個全局標志位,顯得有點麻煩。
事實上,Thread類本身已經擁有對這種情況的完美解決方案――join。
簡單來說,join就是個阻塞方法,在線程1內創建線程2,調用線程2的Join方法,那么線程1將會被阻塞,直到線程2執行完畢。運用到上面的例子就是,在任務4內創建任務2和任務3的線程,調用任務2和任務3的線程的Join方法使任務4阻塞,直到任務2和任務3執行完畢,才繼續執行任務4。這記為方法3,代碼如下
這樣便不需要任何標志位了。這是最理想的解決方案。
另外還有一種解決方案,使用EventWaitHandle
簡單來說,就是方法2的進階版,使用EventWaitHandle控制狀態,而不再使用While循環監聽,但這里仍舊需要兩個全局的EventWaitHandle對象。該方法記為方法4,代碼如下
上述三個優化方案,其實核心思想都是一樣的,都是通過開啟3個線程分別執行2、3、4任務,其中任務4被阻塞(while循環、eventWait.WaitOne,thread.join),當阻塞解除后,繼續執行任務4。也就是說,任務4,其實是一直在等待任務2和任務3的完成。那么,是否有辦法讓任務2和任務3主動通知任務4呢?即,任務2和任務3完成后,主動執行任務4。
方法當然有:異步委托+回調函數
private static void Main(string[] args)
{
CheckUser(); //第一步 驗證用戶
Action step2 = delegate
{
GetDatFromDb(); //從數據庫獲取數據
_m2 = true; //標志位置為true
};
Action step3 = delegate
{
GetDataFromWeb(); //web服務獲取數據
_m3 = true; //標志位置為true
};
step2.BeginInvoke(delegate
{
if (_m2 && _m3) //通過標志位判斷2 3是否都已完成
{
lock (obj)//加鎖
{
_m2 = false;
if (_m3)//二重驗證 防止兩者同時進入
StartProcess(); //執行4
}
}
}, null);
step3.BeginInvoke(delegate
{
if (_m2 && _m3) //通過標志位判斷2 3是否都已完成
{
lock (obj)
{
_m3 = false;
if (_m2)
StartProcess(); //執行4
}
}
}, null);
}
講解下代碼。首先以委托的方式創建了任務2和任務3的委托對象step2和step3。執行這兩個委托的異步調用方法BegInvoke。執行BegInvoke,會創建一個新的線程來執行step2和step3的方法,同時,在執行BeginInvoke的時候還指定了一個回調函數
這個函數會在step2和step3的線程執行完畢后被調用。在這里,我再次使用了標志位來判斷step2和step3是否已經運行完成,同時,為了防止一種特殊情:“step2和step3所執行的時間幾乎相等,他們會同時通過if(_m2&&_m3)判斷,進而執行兩次StartProcess” 在這里加了lock鎖,并且在lock鎖內將標志位重置+二重判斷(這里可以參考單例模式的雙重鎖定原理),確保StarProcess只會執行一次。
如此這般,一個主動通知模式的并行任務便實現了,不過,這種實現方法相較于方法2,實在太過麻煩,尤其在與并發處理方面,個人感覺實用性不太高。
另外,還可以使用觀察者模式實現異步委托+回調函數的效果。
新聞熱點
疑難解答