並行開發適合用於分解計算密集型的任務片段,並將它們分配給多個執行緒。
1、資料的並行處理
有一批資料,需要對每個元素進行相同的操作。該操作是計算密集型,需要耗費一定的時間。Parallel型別的 ForEach 方法就是專門為此設計的。
Parallel的ForEach可以對一系列值進行並行處理。還有類似的解決方案,就是PLINQ(並行LINQ)。
Parallel和PLINQ的區別:PLINQ假設可以使用計算機的所以CPU核,而Parallel會根據CPU的狀態進行動態調整。
Parallel的ForEach是並行版本的foreach版本。Parallel類也提供了並行版本的for迴圈Parallel.For。如果有多個陣列的資料,並且採用了相同的索引,Parallel.For方法就比較適合。
2、並行聚合
在並行操作結束時,需要集合結果,包括累加和、平均值等。
在Parallel中可以使用加鎖的方法,來進行聚合。
PLINQ中聚合的支援,比Parallel類使用更順手。
private static int ParallelSum(IEnumerable<int> values) { return values.AsParallel<int>().Sum(); }
3、並行呼叫
需要並行呼叫一批方法,並且這些方法(大部分)是互相獨立的。 Parallel.Invoke方法就是用於這種場合。
例如並行呼叫一個方法10次:
private static void DoAction10Count(Action action) { Action[] actions = Enumerable.Repeat(action, 10).ToArray(); Parallel.Invoke(actions); }
對於簡單的並行呼叫, Parallel.Invoke是一個不錯的方式。但是,對於每一個輸入都要呼叫一個操作,改用Parallel.Foreach,或者每一個操作要產生一個輸出,改用PLINQ可能更好。
4、動態並行
並行任務的結構和數量要在執行時才能確定,這是一種更復雜的並行程式設計。
任務並行庫(TPL)是以Task類為中心構建的。Parallel和PLINQ都是為了使用方便,對Task類的封裝。
實現動態並行最簡單的做法就是直接使用 Task 類。
在並行中是用Task和在非同步中使用Task完全不同:
並行:並行任務可以使用阻塞的成員函式。例如:Task.WaitAll,Task.Wait,Taks.Result,Taks.WaitAny。並行任務通常也使用AttachedToParent來建立任務之間的父/子關係。
並行任務的建立需要使用Task.Run或者Task.Factory.StartNew方法。
非同步:非同步任務應該避免使用阻塞的成員函式。而應該使用await,Task.WhenAll、Taks.WhenAny。
5、並行LINQ
需要對一批資料進行處理,生成另外一批資料,或者對資料進行統計。
PLINQ為各種操作提供了並行操作,包括過濾、投影、聚合等。
PLINQ適合於對資料流進行操作,一個資料佇列做為輸入,一個資料佇列做為輸出。