微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 为什么PLINQ比循环慢?

假设我有这两种方法
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);

原文地址:https://www.jb51.cc/csharp/97215.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐