编写高质量代码改善C#程序的157个建议——建议84:使用PLINQ

建议84:使用PLINQ

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

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

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

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

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

queryParallel.ForAll((item) =>
{  
    Console.WriteLine(item.ToString());  
}); 

 

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

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

 

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

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

 

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

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

foreach (int item in queryParallel.Take(5))  
{  
    Console.WriteLine(item.ToString());  
}
在顺序查询中,会返回前5个元素。但是在PLINQ中,会选出5个无序的元素。

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

 

 

 

转自:《编写高质量代码改善C#程序的157个建议》陆敏技

posted @ 2015-08-19 18:49  JesseLZJ  阅读(450)  评论(0编辑  收藏  举报