2011-12-16 147 views
5

这两个有什么区别?差异linq和plinq

什么是比较的最佳方式?

它总是更好的plinq?

当我们使用plinq?

+0

这里有一些很好的信息http://www.scip.be/index.php ?Page = ArticlesNET08&Lang = EN – user1231231412 2011-12-16 21:59:16

+0

我认为假设使用PLINQ总是比较好,LINQ将不存在。结果:使用PLINQ并不总是更好。 – jason 2011-12-16 22:03:09

回答

2

PLinq是Linq的并行版本。有些查询可以在多个线程上执行,然后PLinq会提高性能。

但是,其他查询不能并行执行,否则会给出错误结果。所以何时使用PLinq是你应该为每个查询决定的事情,并确保性能实际上增加。

MSDN有很多关于它的文档。

8

Linq是一个技术集合,它们一起工作来解决类似的问题 - 在所有这些技术中你都有一个数据源(xml文件或文件,数据库内容,内存中对象的集合),并且你想要检索部分或全部数据并以某种方式对其执行操作。 LINQ的工作是在这个系列问题的共性使得:

var brithdays = from user in users where 
    user.dob.Date == DateTime.Today && user.ReceiveMails 
    select new{user.Firstname, user.Lastname, user.Email}; 
foreach(bdUser in birthdays) 
    SendBirthdayMail(bdUser.Firstname, bdUser.Lastname, bdUser.Email); 

以及等效(明确使用LINQ相关的类和方法与传统的C#语法):

var birthdays = users 
    .Where(user => user.dob.Date == DateTime.Today) 
    .Select(user => new{user.Firstname, user.Lastname, user.Email}); 
foreach(bdUser in birthdays) 
    SendBirthdayMail(bdUser.Firstname, bdUser.Lastname, bdUser.Email); 

都是例子的代码可以工作,无论它是否会转化为数据库调用,解析xml文档,还是通过对象数组进行搜索。

唯一的区别是什么样的对象users是。如果它是一个列表,数组或其他可枚举集合,它将是linq-to-objects,如果它是一个System.Data.Linq.Table它将是sql的linq。前者会导致内存中操作,后者会导致SQL查询,然后尽可能晚地对内存中的对象进行反序列化。

如果这是一个ParallelQuery - 通过在内存中的枚举集合调用.AsParallel产生 - 那么该查询将在-memroy执行,并行化(大部分时间),以便由多个线程执行的 - 理想地保持每个核心忙于推进工作。

显然这里的想法是更快。当它运作良好时,它确实如此。

虽然有一些缺点。

首先,总会有一些开销让并行化进行,即使在最终不能并行化的情况下也是如此。如果没有足够的数据完成工作,这种开销将超出任何潜在收益。

其次,并行处理的好处取决于可用的内核。如果查询不会阻塞4核机器上的资源,理论上会获得4倍的加速(4个超线程可能会给您带来更多甚至更少,但可能不会超过8倍,线程的CPU的某些部分翻倍并不会明显增加两倍)。对单核或者处理器亲和性的相同查询意味着只有一个核心可用(例如,在“web-garden”模式下的web服务器),那么没有加速。如果资源受到阻碍,仍然可以获得收益,但收益取决于机器。

第三,如果有任何共享资源(可能是一个收集结果输出到)在非线程安全的方式使用,它可以走得相当严重错误与不正确的结果,死机等

四,如果以线程安全的方式使用共享资源,并且线程安全来自锁定,则可能存在足够的争用成为解除并行化的所有好处的瓶颈。第五,如果你有一个四核机器在四个不同的线程上或多或少地使用相同的算法(可能在客户端 - 服务器情况下由于四个客户端,或者来自一组类似的桌面情况在这个过程中任务更高),那么他们就会尽可能地利用这些核心。将算法中的工作分开以便在所有四个内核中进行处理意味着您已经从四个线程移动到每个内核,16个线程与四个内核交战。充其量也是一样的,可能的开销会让它稍微恶化。

可以仍然是很多情况下的主要胜利,但上面应该说明它并不总是。

0

考虑避免anonymous typesPLINQ工作时,因为根据Threading in C#, by Joe Albahari

匿名类型(即类和因此引用类型)招致基于堆的分配和随后的垃圾收集的成本。

(...)

基于堆栈的分配是高度并行(因为每个线程都有自己的堆栈),而所有线程都必须为同一个堆竞争 - 由单一的内存管理和垃圾收集管理。

2

由于进行AsParallel透明并行化LINQ查询,出现这样的问题,“你为什么不只是微软并行标准查询操作符,使PLINQ默认?”

有许多的原因选择在进近中。首先,为了使PLINQ有用,必须进行合理数量的计算密集型工作,以便将其用于工作线程。大多数LINQ to Objects查询的执行速度非常快,不仅平行化不必要,而且分区,整理和协调额外线程的开销实际上可能会减慢速度。

此外:

一个PLINQ查询(默认情况下)的输出可以从LINQ查询不同相对于元件排序。

下面的查询操作阻止并行查询,除非源元素是在原来的标定位置:

走,TakeWhile,跳过和SkipWhile选择,的SelectMany的索引的版本,并ElementAt的大多数查询运算符更改元素的索引位置(包括删除元素的位置,如Where)。这意味着如果你想使用前面的操作符,他们通常需要在查询的开始。

下面的查询操作是并行的,但使用昂贵的分区策略,有时可以比顺序处理慢:

加入,的GroupBy,群组加入,层次分明,联盟,交叉,除了在总量上运营商的种子重载他们的标准化身不是可并行化的 - PLINQ提供特殊的重载来处理这个问题。

何时使用PLINQ 很容易在现有的应用程序中搜索LINQ查询并试验并行化。这通常是徒劳的,因为LINQ显然是最好的解决方案的大多数问题倾向于执行得非常快,所以不会从并行化中受益。一个更好的方法是找到一个CPU密集型瓶颈,然后考虑“这可以表示为LINQ查询吗?”(这种重组的一个受欢迎的副作用是LINQ通常会使代码更小且更具可读性。)

PLINQ非常适合于令人尴尬的并行问题。它也适用于结构化阻塞任务,例如一次调用多个Web服务(请参阅调用阻塞或I/O密集函数)。

PLINQ对于成像来说可能是一个糟糕的选择,因为将数百万像素整理成输出序列会造成瓶颈。相反,最好将像素直接写入数组或非托管内存块,并使用并行类或任务并行性来管理多线程。 (但是,如果图像处理算法自然适用于LINQ,则可能会失败使用ForAll的结果整理。)