並行開發基礎

_York發表於2018-06-13

  並行開發適合用於分解計算密集型的任務片段,並將它們分配給多個執行緒。

 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適合於對資料流進行操作,一個資料佇列做為輸入,一個資料佇列做為輸出。

 

相關文章