差分linq和plinq
这两者有什么区别 最好的比较方法是什么 这总是更好吗差分linq和plinq,linq,plinq,Linq,Plinq,这两者有什么区别 最好的比较方法是什么 这总是更好吗 当我们使用plinq时?plinq是Linq的并行版本。一些查询可以在多个线程上执行,然后PLinq可以提高性能 然而,其他查询不能并行执行,或者如果这样做会给出错误的结果。因此,对于每个查询,您应该决定何时使用PLinq,并确保性能实际得到提高 有很多文档。Linq是一系列技术的集合,它们共同解决一系列类似的问题——在所有这些技术中,您都有一个数据源(xml文件、数据库内容、内存中的对象集合),您希望检索部分或全部数据,并以某种方式对其进行
当我们使用plinq时?plinq是Linq的并行版本。一些查询可以在多个线程上执行,然后PLinq可以提高性能 然而,其他查询不能并行执行,或者如果这样做会给出错误的结果。因此,对于每个查询,您应该决定何时使用PLinq,并确保性能实际得到提高
有很多文档。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);
以及等效的(使用传统C#语法显式使用Linq相关的类和方法):
这两个示例都是可以工作的代码,无论它是转换为数据库调用、解析xml文档还是通过对象数组进行搜索
唯一的区别是用户是什么类型的对象。如果它是列表、数组或其他可枚举集合,则它将是linq到对象,如果它是System.Data.linq.Table
则它将是linq到sql。前者将导致内存中的操作,后者将在SQL查询中,然后尽可能晚地反序列化到内存中的对象
如果它是一个并行查询
——通过调用内存中可枚举集合上的.aspallel
生成——那么查询将在memroy中执行,并行化(大部分时间)以便由多个线程执行——理想情况下,使每个核心都忙于向前推进工作
显然,这里的想法是更快。当它运行良好时,它就会运行
不过也有一些缺点
首先,进行并行化总是有一些开销,即使在无法并行化的情况下也是如此。如果在数据方面没有做足够的工作,这种开销将超过任何潜在的收益
其次,并行处理的好处取决于可用的内核。如果查询不会阻塞4核机器上的资源,理论上可以获得4倍的速度(4个超线程可能会给您带来更多甚至更少的速度,但可能不会是8倍,因为超线程将CPU的某些部分增加一倍并不会带来明显的两倍增长)。如果在单个内核上执行相同的查询,或者处理器关联意味着只有一个内核可用(例如,处于“web garden”模式的web服务器),那么就没有加速。如果资源被阻塞,仍然会有收益,但收益取决于机器
第三,如果以非线程安全的方式使用任何共享资源(可能是输出到的一个集合结果),则可能会出现错误结果、崩溃等严重错误
第四,如果有一个共享资源以线程安全的方式使用,并且线程安全来自于锁定,那么可能会有足够的争用成为瓶颈,使并行化带来的所有好处付诸东流
第五,如果您有一台四核机器在四个不同线程上或多或少地使用相同的算法(可能是由于四个客户机而在客户机-服务器的情况下,或者是在一个桌面上,因为在这个过程中有一组类似的任务),那么他们总是在充分利用这些核心。将算法中的工作拆分,以便在所有四个核之间进行处理,这意味着您已经从每个使用一个核的四个线程转移到了争夺四个核的16个线程。充其量也会是一样的,而且可能的间接费用会使情况稍微恶化
在很多情况下,它仍然是一个重大的胜利,但上述情况应该清楚地表明,它并不总是如此。在使用时考虑避免,因为根据:
匿名类型(作为类和引用类型)会产生基于堆的分配和后续垃圾收集的成本
(……)
基于堆栈的分配是高度并行的(因为每个线程都有自己的堆栈),而所有线程都必须竞争相同的堆—由单个内存管理器和垃圾收集器管理
我还想知道何时使用PLINQ而不是LINQ,所以我运行了一些测试
摘要:
在决定是否使用LINQ或PLINQ运行查询时,有两个问题需要回答
运行查询涉及多少次迭代(集合中有多少个对象)
迭代涉及多少工作
使用LINQ,除非PLINQ性能更好。如果查询集合涉及太多迭代和/或每个迭代涉及太多工作,PLINQ的性能可能比LINQ更高
但随后出现了两个难题:
多少次迭代就是太多的迭代
多少工作就是太多的工作
我的建议是测试您的查询。使用LINQ和PLINQ测试一次,然后比较两个结果
测试1:通过增加集合中对象的数量来增加查询中的迭代次数。
初始化PLINQ的开销大约需要20毫秒。如果没有利用PLINQ的优势,这是浪费时间,因为LINQ有0毫秒的开销
每次迭代所涉及的工作对于每个测试都是相同的。这项工作保持在最低限度
功的定义:整数(集合中的对象)乘以10
当迭代100万个对象时,每次迭代所需的工作量最小,PLINQ比LINQ快。虽然在一个专业的环境中,我从来没有质疑过,甚至没有初始化过一个
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);
╔═══════════╦═══════════╦════════════╗
║ # 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 ║
╚═══════════╩═══════════╩════════════╝
╔══════════════╦═══════════╦════════════╗
║ # 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 ║
╚══════════════╩═══════════╩════════════╝
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;
}
}
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;
}
}