这两者之间的区别是什么?
最好的比较方式是什么?
它总是更好的plinq?
当我们使用plinq的时候?
发布于 2011-12-18 05:03:24
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,那么它就是linq to sql。前者会导致内存中的操作,后者在SQL查询中,然后会尽可能晚地反序列化为内存中的对象。
如果它是一个ParallelQuery --通过在内存中的可枚举集合上调用.AsParallel而产生--那么查询将在内存中执行,(大多数情况下)是并行的,以便由多个线程执行-理想情况下,让每个核心忙于向前推进工作。
显然,这里的想法是更快。当它运行良好时,它确实如此。
不过,这也有一些缺点。
首先,让并行化进行总是有一些开销,即使在它最终不可能并行化的情况下也是如此。如果在数据上没有做足够的工作,这种开销将超过任何潜在的收益。
其次,并行处理的好处取决于可用的内核。使用一个不会阻塞4核机器上的资源的查询,理论上您可以获得4倍的速度(4个超线程可能会给您带来更多甚至更少,但可能不会是8倍,因为CPU某些部分的超线程加倍不会带来明显的两倍增长)。在单核上使用相同的查询,或者处理器亲和性意味着只有一个核可用(例如,web服务器处于“网络花园”模式),则不会有加速。如果存在资源阻塞,仍然可以获得收益,但收益取决于机器。
第三,如果以非threadsafe的方式使用任何共享资源(可能是以非threadsafe方式输出的集合结果),它可能会出现非常严重的错误,结果不正确,崩溃等。
第四,如果以线程安全的方式使用共享资源,并且线程安全来自锁定,那么可能会有足够的争用成为瓶颈,从而取消并行化带来的所有好处。
第五,如果你有一台四核机器,在四个不同的线程上运行或多或少相同的算法(可能是在客户端-服务器的情况下,因为有四个客户端,或者在桌面上,因为进程中有一组类似的任务),那么它们已经充分利用了这些内核。将算法中的工作拆分,以便跨所有四个核心进行处理,这意味着您已经从使用一个核心的四个线程转移到了争夺四个核心的16个线程。充其量也是一样的,可能的管理费用会让事情变得更糟。
在许多情况下,It 仍然是一个重大胜利,但上面的情况应该清楚地表明,它不会总是如此。
发布于 2018-07-23 21:15:08
我还想知道什么时候使用PLINQ而不是LINQ,所以我运行了一些测试。
摘要:在决定使用LINQ PLINQ来运行查询时,有两个问题需要回答。
除非PLINQ性能更好,否则请使用LINQ。如果查询集合涉及太多迭代和/或每次迭代涉及太多工作,则PLINQ可能比LINQ性能更高。
但随后出现了两个困难的问题:
我的建议是对查询进行测试。使用LINQ测试一次,使用PLINQ测试一次,然后比较两个结果。
测试1:通过增加集合中的对象数量来增加查询中的迭代次数。
初始化PLINQ的开销大约需要20ms。如果PLINQ的优势没有被利用,这是浪费时间,因为LINQ有0毫秒的开销。
每次迭代中涉及的工作对于每次测试都是相同的。这项工作被保持在最低限度。
工作的定义:将(集合中的对象)乘以10。
当迭代100万个对象时,每次迭代只涉及最少的工作,PLINQ比LINQ更快。虽然在专业环境中,我从未查询或初始化内存中1000万个对象的集合,因此这可能是一个不太可能的场景,PLINQ恰好优于LINQ。
╔═══════════╦═══════════╦════════════╗
║ # Objects ║ LINQ (ms) ║ PLINQ (ms) ║
╠═══════════╬═══════════╬════════════╣
║ 1 ║ 1 ║ 20 ║
║ 10 ║ 0 ║ 18 ║
║ 100 ║ 0 ║ 20 ║
║ 1k ║ 0 ║ 23 ║
║ 10k ║ 1 ║ 17 ║
║ 100k ║ 4 ║ 37 ║
║ 1m ║ 36 ║ 76 ║
║ 10m ║ 392 ║ 285 ║
║ 100m ║ 3834 ║ 2596 ║
╚═══════════╩═══════════╩════════════╝测试2:增加迭代中涉及的工作
我将集合中的对象数量设置为始终为10,因此查询涉及的迭代次数较少。对于每个测试,我增加了处理每个迭代所涉及的工作。
工作的定义:将(集合中的对象)乘以10。
增加工作的定义:增加迭代次数,使int乘以10。
PLINQ在查询集合时速度更快,因为当工作迭代中的迭代次数增加到1000万次时,工作量会显着增加,并且我得出结论,当单个迭代涉及如此多的工作量时,PLINQ优于LINQ。
此表中的"# Iterations“表示工作迭代中的迭代次数。请参阅下面的测试2代码。
╔══════════════╦═══════════╦════════════╗
║ # Iterations ║ LINQ (ms) ║ PLINQ (ms) ║
╠══════════════╬═══════════╬════════════╣
║ 1 ║ 1 ║ 22 ║
║ 10 ║ 1 ║ 32 ║
║ 100 ║ 0 ║ 25 ║
║ 1k ║ 1 ║ 18 ║
║ 10k ║ 0 ║ 21 ║
║ 100k ║ 3 ║ 30 ║
║ 1m ║ 27 ║ 52 ║
║ 10m ║ 263 ║ 107 ║
║ 100m ║ 2624 ║ 728 ║
║ 1b ║ 26300 ║ 6774 ║
╚══════════════╩═══════════╩════════════╝测试1代码:
class Program
{
private static IEnumerable<int> _numbers;
static void Main(string[] args)
{
const int numberOfObjectsInCollection = 1000000000;
_numbers = Enumerable.Range(0, numberOfObjectsInCollection);
var watch = new Stopwatch();
watch.Start();
var parallelTask = Task.Run(() => ParallelTask());
parallelTask.Wait();
watch.Stop();
Console.WriteLine($"Parallel: {watch.ElapsedMilliseconds}ms");
watch.Reset();
watch.Start();
var sequentialTask = Task.Run(() => SequentialTask());
sequentialTask.Wait();
watch.Stop();
Console.WriteLine($"Sequential: {watch.ElapsedMilliseconds}ms");
Console.ReadKey();
}
private static void ParallelTask()
{
_numbers
.AsParallel()
.Select(x => DoWork(x))
.ToArray();
}
private static void SequentialTask()
{
_numbers
.Select(x => DoWork(x))
.ToArray();
}
private static int DoWork(int @int)
{
return @int * 10;
}
}测试2代码:
class Program
{
private static IEnumerable<int> _numbers;
static void Main(string[] args)
{
_numbers = Enumerable.Range(0, 10);
var watch = new Stopwatch();
watch.Start();
var parallelTask = Task.Run(() => ParallelTask());
parallelTask.Wait();
watch.Stop();
Console.WriteLine($"Parallel: {watch.ElapsedMilliseconds}ms");
watch.Reset();
watch.Start();
var sequentialTask = Task.Run(() => SequentialTask());
sequentialTask.Wait();
watch.Stop();
Console.WriteLine($"Sequential: {watch.ElapsedMilliseconds}ms");
Console.ReadKey();
}
private static void ParallelTask()
{
_numbers
.AsParallel()
.Select(x => DoWork(x))
.ToArray();
}
private static void SequentialTask()
{
_numbers
.Select(x => DoWork(x))
.ToArray();
}
private static int DoWork(int @int)
{
const int numberOfIterations = 1000000000;
for (int i = 0; i < numberOfIterations; i++)
{
@int = @int * 10;
}
return @int;
}
}发布于 2011-12-17 06:01:31
PLinq是Linq的并行版本。一些查询可以在多个线程上执行,然后PLinq可以提高性能。
然而,其他查询不能并行执行,否则会给出错误的结果。因此,何时使用PLinq是您应该为每个查询决定的,并确保性能实际提高。
MSDN有很多关于它的文档。
https://stackoverflow.com/questions/8540646
复制相似问题