C# 并行编程 之 PLINQ 基本使用

PLINQ Summary

LINQ (LINQ) Language Integrated Query 可以方便的查询并处理不同数据源的数据。PLINQ Parallel LINQ不光拥有LINQ的功能,还添加了并行操作的接口,以方便使用并提高效率。

一个简单的例子

用一个简单的例子足以说明PLINQ的使用。
简单的说明:
第一部分:先在一个文档中查询包含字母 “a”的单词首先使用 LINQ进行查询10000次,然后使用PLINQ进行同样的测试,看看效率有多少提高。 AsParallel() 是主要用到的接口。

第二部分:计算Short类型所有数字的和,同样测试两次使用LINQ和PLINQ。

第三部分:测试PLINQ的查找排序功能。使用的接口分别为AsOrdered()和orderby
AsOrdered:保持数据在数据源中的顺序不变。
orderby:按用户指定的顺序进行排序,升序/降序

示例程序:

using System; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Diagnostics; using System.Linq; using System.IO; namespace Sample6_1_plink_basic { class Program { static int SumDefault(int[] array) { return array.Sum(); } static int SumAsParallel(int[] array) { return array.AsParallel().Sum(); } static string[] words = { Day, Car, Land, Road, Sea, Mountain, River}; static void Main(string[] args) { var customers = System.IO.File.ReadAllLines(@D: estdirCSParallel_ProgramSample6-1 plink basic arget.txt); int nCounter = 0; Console.WriteLine(============================================================); Console.WriteLine(TEST NORMAL LINQ); Console.WriteLine(============================================================); var swatchpn = Stopwatch.StartNew(); for (int i = 0; i < 10000; i++) { var normalkeyLetters = from line in customers let keys = line.Split(' ') from key in keys where (key.Contains('a')) select key; var normalkeyList = normalkeyLetters.ToList(); nCounter = normalkeyList.Count(); } swatchpn.Stop(); Console.WriteLine(Word with letter a = {0}, nCounter); Console.WriteLine(LINQ Use Time: {0}, swatchpn.Elapsed); Console.WriteLine( ); Console.WriteLine(============================================================); Console.WriteLine(TEST PARALLEL LINQ); Console.WriteLine(============================================================); nCounter = 0; var swatchp = Stopwatch.StartNew(); for (int i = 0; i < 10000; i++) { var keyLetters = from line in customers.AsParallel() let keys = line.Split(' ') from key in keys.AsParallel() where (key.Contains('a')) select key; var keyList = keyLetters.ToList(); nCounter = keyList.Count(); } swatchp.Stop(); Console.WriteLine(Word with letter a = {0}, nCounter); Console.WriteLine(PLINQ Use Time: {0}, swatchp.Elapsed); // Generate array. int[] array = Enumerable.Range(0, short.MaxValue).ToArray(); const int m = 10000; var s1 = Stopwatch.StartNew(); for (int i = 0; i < m; i++) { SumDefault(array); } s1.Stop(); var s2 = Stopwatch.StartNew(); for (int i = 0; i < m; i++) { SumAsParallel(array); } s2.Stop(); Console.WriteLine( ); Console.WriteLine(============================================================); Console.WriteLine(CALCULATE SUMMARY TEST); Console.WriteLine(============================================================); Console.WriteLine(Default Summary: + ((double)(s1.Elapsed.TotalMilliseconds * 1000000) / m).ToString(0.00 ns)); Console.WriteLine(Parallel Summary: + ((double)(s2.Elapsed.TotalMilliseconds * 1000000) /m).ToString(0.00 ns)); Console.WriteLine( ); Console.WriteLine(============================================================); Console.WriteLine(Parallel ASOrder Test); Console.WriteLine(============================================================); var orderwords = from word in words.AsParallel().AsOrdered() where (word.Contains('a')) select word; var orderletterList = orderwords.ToList(); for (int i = 0; i < orderletterList.Count; i++) { Console.WriteLine(orderletterList[i]); } Console.WriteLine( ); Console.WriteLine(============================================================); Console.WriteLine(Parallel OrderBy Test); Console.WriteLine(============================================================); var orderbywords = from word in words.AsParallel() where (word.Contains('a')) orderby word ascending select word; var orderbyletterList = orderbywords.ToList(); for (int i = 0; i < orderbyletterList.Count; i++) { Console.WriteLine(orderbyletterList[i]); } Console.ReadKey(); } } }

测试结果:
C# 并行编程 之 PLINQ 基本使用

测试其实运行过多次,关于单词的测试LINQ的结果在32至34秒,PLINQ大概在16至19秒,大约有50%的提升。

关于PLINQ中的数据分区

PLINQ使用多个任务对同一个数据源进行处理,然后汇总,使得效率提高。但并行执行的任务应该处理数据的哪个部分,怎样对数据进行合理的划分,并且分配给任务是很重要的,它会严重的影响效率。但开发者并不太可能去真正的控制PLINQ去采用哪种分区方式,了解一下它的内部机理在优化程序性能时会有一定的帮助。

PLINQ中有四种数据的划分方式:

范围划分:用于可索引的数据源,例如数组和列表。PLINQ会查找数据源的IList接口,如果找到了,它就会采取范围据划分方式,将数据分解为与可用的逻辑内核数目相等的分区。PLINQ可以确切的知道数据规模,而且可以直接访问其中的任意元素。


数据块划分:适用于任何数据源,用于不可索引的数据,不同任务此时得到的是数据块,块的大小可能不一样。


交错式分区:这种方式对在数据源顶部对数据项进行处理的情况进行了优化。当查询包括SkipWhile和TakeWhile时会采用这种方式。此时每个任务对应的是一小组数据(简称条纹)。任务通过简单的计算可以判断出数据对应的条纹,所以任务间并不需要同步。


散列分区:主要针对数据比较进行了优化。它在数据和任务间建立了通道,带有相同散列码的数据项会被发送到同一个任务中,这样有可能的匹配便会在一个数据分区中,从而简化了比较的过程,减少了不同任务间的数据共享。采用这种方式时分发数据时可能会有较大的开销,但数据比较时效率会提高。

分类:默认分类 时间:2015-03-03 人气:2
本文关键词:
分享到:

相关文章

Copyright (C) quwantang.com, All Rights Reserved.

趣玩堂 版权所有 京ICP备15002868号

processed in 0.116 (s). 10 q(s)