为什么PLINQ比for循环慢
本文关键字:循环 for PLINQ 为什么 | 更新日期: 2023-09-27 18:19:15
假设我有两个方法:
public BigInteger PFactorial(int n)
{
return Enumerable.Range(1, n)
.AsParallel()
.Select(i => (BigInteger)i)
.Aggregate(BigInteger.One, BigInteger.Multiply);
}
public BigInteger Factorial(int n)
{
BigInteger result = BigInteger.One;
for(int i = 1; i <= n; i++)
result *= i;
return result;
}
我得到的结果如下:
PFactorial(25000) -> 0,9897 seconds
Factorial(25000) -> 0,9252 seconds
我知道PLINQ有一些开销,因为线程设置,但有这么大的n
,我希望PLINQ更快。
下面是另一个结果:
PFactorial(50000) -> 4,91035 seconds
Factorial(50000) -> 4,40056 seconds
对于聚合来说,并行是不可能的。至少在我的脑海里无法想象。无论如何,您应该通过将列表分成块来实现并行化。找到这些结果。最后把小块相乘。这是PLinq的快捷方式。
static public BigInteger PFactorial(int n)
{
var range = Enumerable.Range(1, n).Select(x => (BigInteger) x).AsParallel();
var lists = range.GroupBy(x => x/(n/Environment.ProcessorCount)).Select(x => x.AsEnumerable());
var results = lists.Select(x => x.Aggregate(BigInteger.One, BigInteger.Multiply));
var result = results.Aggregate(BigInteger.One, BigInteger.Multiply);
return result;
}
测试PFactorial(50000) -> 1,41 seconds
Factorial(50000) -> 2,69 seconds
编辑:正如Servy和Chatzigiannakis所提到的,如果你不使用种子,它可以完美地使用并行化,你会得到与上面几乎相同的结果(快一点)。
return Enumerable.Range(1,n).Select(x => (BigInteger)x).AsParallel().Aggregate(BigInteger.Multiply);
请不要认为pLinQ总是比LinQ快。基于多条件的PLinQ执行时间
仅在元素较多且有一些CPU密集型查询时使用PLinQ。我建议在函数中使用System.Threading.Thread.Sleep(1)
来模拟CPU负载作为周期延迟,然后从LinQ和PlinQ调用该函数10000次。然后你就能看到区别了。请在这里找到示例
您当前的函数Factorial实际上没有执行任何CPU密集型任务,并且导致PLinQ花费更多时间,因为它将查询在多个核心中运行,并将单个核心的结果合并到单个输出,这比正常情况下花费更多时间。
还要确保您使用的是多核处理器(至少4个将为您提供良好的分析)