.NET 实现并行的几种方式(三)
在前兩篇隨筆中,先后介紹了?Thread?、ThreadPool?、IAsyncResult (即 APM系列)?、Task??、TPL (Task Parallel Library)。
寫到這些筆者突然意識到 還有一個EMP系列沒有寫,在這里補充一下:
六、?EAP?、EAP中的典型代表是?WebClient:
EAP系列采用 ***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("開始異步下載數據");?
七、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("并行查詢執行完畢");});}??
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
?
總結
以上是生活随笔為你收集整理的.NET 实现并行的几种方式(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 考研热度攀升:未来几年还会升温 将培养输
- 下一篇: [你必须知道的.NET]第十七回:貌合神