使用PLINQ

LINQ最基本的功能就是对集合进行遍历查询,并在此基础上对元素进行操作。仔细推敲会发现,并行编程简直就是专门为这一类应用准备的。因此,微软 专门为LINQ拓展了一个类ParallelEnumerable(该类型也在命名空间System.Linq中),它所提供的扩展方法会让LINQ支持 并行计算,这就是所谓的PLINQ。

传统的LINQ计算是单线程的,PLINQ则是并发的、多线程的,我们通过下面这个示例就可以看出这个区别:

  1. static void Main(string[] args)  
  2. {  
  3.     List<int> intList = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };  
  4.     var query = from p in intList select p;  
  5.     Console.WriteLine("以下是LINQ顺序输出:");  
  6.     foreach (int item in query)  
  7.     {  
  8.         Console.WriteLine(item.ToString());  
  9.     }  
  10.     Console.WriteLine("以下是PLINQ并行输出:");  
  11.     var queryParallel = from p in intList.AsParallel() select p;  
  12.     foreach (int item in queryParallel)  
  13.     {  
  14.         Console.WriteLine(item.ToString());  
  15.     }  

LINQ的输出会按照intList中的索引顺序打印出来。而PLINQ的输出是杂乱无章的。

并行输出还有另外一种方式可以处理,那就是对queryParallel求ForAll:

  1. queryParallel.ForAll((item) => 
  2. {  
  3.     Console.WriteLine(item.ToString());  
  4. }); 

但是这种方法会带来一个问题,如果要将并行输出后的结果进行排序,ForAll会忽略掉查询的AsOrdered请求。如下所示:

  1. var queryParallel = from p in intList.AsParallel().AsOrdered() select p;  
  2. queryParallel.ForAll((item) => 
  3. {  
  4.     Console.WriteLine(item.ToString());  
  5. }); 

AsOrdered方法可以对并行计算后的队列进行重新组合,以便保持顺序。可是在ForAll方法中,它所完成的输出仍是无序的。如果要保持AsOrdered方法的需求,我们应当始终使用第一种并行方式,即:

  1. var queryParallel = from p in intList.AsParallel().AsOrdered() select p;  
  2. foreach (int item in queryParallel)  
  3. {  
  4.     Console.WriteLine(item.ToString());  

在并行查询后再进行排序,会牺牲掉一定的性能。一些扩展方法默认会对元素进行排序,这些方法包括:OrderBy、 OrderByDescending、ThenBy和ThenByDescending。在实际的使用中,一定要注意到各种方式之间的差别,以便程序按照 我们的设想运行。

还有一些其他的查询方法,比如Take。如果我们这样编码:

  1. foreach (int item in queryParallel.Take(5))  
  2. {  
  3.     Console.WriteLine(item.ToString());  

在顺序查询中,会返回前5个元素。但是在PLINQ中,会选出5个无序的元素。

建议在对集合中的元素项进行操作的时候使用PLINQ代替LINQ。但是要记住,不是所有并行查询的速度都会比顺序查询快,在对集合执行某些方法 时,顺序查询的速度会更快一点,如方法ElementAt等。在开发中,我们应该仔细辨别这方面的需求,以便找到最佳的解决方案。
原文地址:https://www.cnblogs.com/shihao/p/2456821.html