程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> .NET 實現並行的幾種方式(三),.net並行

.NET 實現並行的幾種方式(三),.net並行

編輯:關於.NET

.NET 實現並行的幾種方式(三),.net並行


本隨筆續接:.NET 實現並行的幾種方式(二)

在前兩篇隨筆中,先後介紹了 Thread 、ThreadPool 、IAsyncResult (即 APM系列) 、Task  、TPL (Task Parallel Library)。

寫到這些筆者突然意識到 還有一個EMP系列沒有寫,在這裡補充一下:

六、 EPM 、EPM中的典型代表是 WebClient:

EPM系列采用 ***Async方法 + ***Completed事件 的編碼規范,不做太多解釋、具體的demo如下:

var address = "http://www.cnblogs.com/08shiyan/"; WebClient client = new WebClient(); Uri uri = new Uri(address); client.DownloadStringCompleted += new DownloadStringCompletedEventHandler((object sender, DownloadStringCompletedEventArgs e) => { this.txtTip.SetTip("下載完成"); }); client.DownloadStringAsync(uri); this.txtTip.SetTip("開始異步下載數據"); WebClient

 

七、PLINQ 、LINQ的並行版本

1) 首先看一下PLINQ在 MSDN 中的介紹 : 

並行 LINQ (PLINQ) 是 LINQ 模式的並行實現。 PLINQ 查詢在許多方面類似於非並行 LINQ to Objects 查詢。 與順序 LINQ 查詢一樣,PLINQ 查詢對任何內存中 IEnumerable 或 IEnumerable<T> 數據源進行操作,並推遲執行,這意味著在枚舉查詢之前不會開始執行這些操作。 主要區別是 PLINQ 嘗試充分利用系統中的所有處理器。 它利用所有處理器的方法是,將數據源分成片段,然後在多個處理器上對單獨工作線程上的每個片段並行執行查詢。 在許多情況下,並行執行意味著查詢運行速度顯著提高。

通過並行執行,PLINQ 通常只需向數據源添加 AsParallel 查詢操作,即可在某些查詢類型的舊版代碼上獲得顯著的性能改進。 但是,並行可能引入其自己的復雜性,因此並非所有查詢操作在 PLINQ 中都運行得更快。 事實上,並行降低了某些查詢的速度。 因此,您應了解諸如排序等問題如何影響並行查詢。 有關詳細信息,請參閱 Understanding Speedup in PLINQ。

從介紹中、我們可以明確三點:

1、PLINQ是LINQ的並行版本、它擁有和LINQ一樣一樣強大的基因。

2、PLINQ會嘗試充分利用所有處理器、(PLINQ在 MSDN 中的介紹 最多是64個),因此許多情況下PLINQ可以顯著提高的並行效率,尤其是CPU密集型計算的並行率。

3、並非所有查詢操作在 PLINQ 中都運行得更快。

 

2)PLINQ與LINQ的無縫連接

PLINQ 的實現基礎是 :ParallelQuery<TSource>,LINQ的實現基礎是:IEnumerable<TSource>, 當然這裡說的都是泛型版本。

如下的兩個擴展方法、可輕易實現PLINQ和LINQ間的轉化。

public static ParallelQuery<TSource> AsParallel<TSource>(this IEnumerable<TSource> source);
public static IEnumerable<TSource> AsSequential<TSource>(this ParallelQuery<TSource> source);

 

3)簡單Demo

/// <summary> /// PLinq:Linq的並行版本 /// </summary> public void Demo1() { Task.Run(() => { var result = Enumerable.Range(1, 10).AsParallel().Where(e => { SetTip("開始 " + e); SetTip("休眠 " + e); Thread.Sleep(1000); SetTip("結束 " + e); return e > 5; }); SetTip("打印結果"); foreach (var item in result) { SetTip(item.ToString()); } SetTip("並行查詢執行完畢"); }); } PLinq:Linq的並行版本

  

4)PLINQ與LINQ的微妙關系

在功能上:PLINQ幾乎實現了LINQ的全部功能、且方法名都是一致的。

在時間性能上:PLINQ will always attempt to execute a query at least as fast as the query would run sequentially. 

  因此、PLINQ在執行查詢之前會進行一次“預判”,如果發現了某些情況,當前可能會自動轉為順序執行、即LINQ模式。

 

5)當查詢包含以下情況時,PLINQ將會默認按照順序模式執行

  • 包含 Select 子句、已建立索引的 Where 子句、已建立索引的 SelectMany 子句或 ElementAt 子句的查詢(在排序或篩選運算符移除或重新排列了索引後)。

  • 包含 Take、TakeWhile、Skip、SkipWhile 運算符並且源序列中的索引未采用原始順序的查詢。

  • 包含 Zip 或 SequenceEquals 的查詢,除非其中一個數據源具有按原始順序排列的索引,並且另一個數據源可建立索引 (例如:數組 或 IList(T)).

  • 包含 Concat 的查詢,除非將其應用到可建立索引的數據源。

  • 包含 Reverse 的查詢,除非應用到可建立索引的數據源。

 

6) 強制PLINQ並行查詢

我們可以通過 WithExecutionMode<TSource> 運算符,指定 ParallelExecutionMode.ForceParallelism  強制PLINQ並行查詢。

 

7)ForAll 多線程枚舉

你有可能對“多線程枚舉”這個詞感到莫名其妙,先看圖:

 

如果你用 foreach、即 IEnumerable 接口枚舉並行查詢結果,其流程圖如第一個所示:即多個線程並行完成後,

還會有一個Merger操作,使結果回到使用該數據的主線程、並將數據合並。

而 ForAll是並行版本的Foreach.

 

8)其他運算符

1、AsOrdered<TSource>  PLINQ查詢默認是不保留順序的。該運算符可保留源序列的順序(會產生額外的排序開銷、降低性能)。

2、AsUnordered<TSource>  是 AsOrdered<TSource>的反操作、對後續操作不在保持序列,可用於中間查詢、提高性能。

  AsUnordered can be called anywhere in the query; it does not need to be called immediately after AsParallel.

3、WithCancellation<TSource> 用於取消操作

4、WithDegreeOfParallelism<TSource>   用以指定最大可使用的處理器數量。

 

9)補充:影響PLINQ查詢性能的因素

 

 

附,Demo : http://files.cnblogs.com/files/08shiyan/ParallelDemo.zip

 

參見更多:隨筆導讀:同步與異步


(未完待續...)

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved