为什么我的AsOrdered PLINQ查询比我的无序查询更快

Gil*_*les 6 .net c# plinq

我写了一些基本的示例代码来熟悉PLINQ.

我遇到了一些奇怪的东西.我不知道我的代码中是错误还是我对PLINQ的理解错误.

MSDN文档指出,添加AsOrdered()将以可能的性能成本保留调用的顺序.

我写了一些单元测试,并注意到文档中所述的对结果集的顺序的影响.但我已经看到了对性能的负面影响.

这是我的方法:

public IEnumerable<int> ParallelCalculatePrimesUpTo(int maxValue)
{
    return from number in Enumerable.Range(1, maxValue).AsParallel()
            where IsPrime(number)
            select number;
}

public IEnumerable<int> OrderedParallelCalculatePrimesUpTo(int maxValue)
{
    return from number in Enumerable.Range(1, maxValue).AsParallel().AsOrdered()
            where IsPrime(number)
            select number;
}
Run Code Online (Sandbox Code Playgroud)

而我非常简单的基准测试

    [TestMethod]
    public void SimplisticBenchmark6()
    {
        var primeNumberCalculator = new PrimeNumberCalculator();

        var startTime = DateTime.Now;

        primeNumberCalculator.ParallelCalculatePrimesUpTo(10000000).ToList();

        var totalTime = DateTime.Now - startTime;

        Console.WriteLine(totalTime);
    }

    [TestMethod]
    public void SimplisticBenchmark7()
    {
        var primeNumberCalculator = new PrimeNumberCalculator();

        var startTime = DateTime.Now;

        primeNumberCalculator.OrderedParallelCalculatePrimesUpTo(10000000).ToList();

        var totalTime = DateTime.Now - startTime;

        Console.WriteLine(totalTime);
    }
Run Code Online (Sandbox Code Playgroud)

无论我多久运行一次这个测试,有序版本都会打败无序版本.我的四核计算机上的订购速度大约快4秒.对于有序的一个,我得到大约18秒,对于无序的一个,我得到22秒.我在两天的时间内完成了几十次测试(在那些日子之间重新启动).

如果我降低数10 000 000 6 000 000,差异仍然存在,只是不显着,如果我它降低到3 000 000,它是关于相同的速度.

我尝试按执行顺序运行测试,结果是一样的.

以下是在PLINQ查询中调用的IsPrime方法:

// uses inneficient trial division algorithm
private bool IsPrime(int number)
{
    if (number == 1)
        return false;

    for (int divisor = 2; divisor <= Math.Sqrt(number); divisor++)
    {
        if (number % divisor == 0)
            return false;
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

这解释了什么?

Lar*_*ann 1

您能告诉我们 4 个不同核心的 CPU 利用率是多少吗?AsOrdered() 可能会强制在同一核心上发生更多顺序调用。随着局部性的改进,硅级缓存和分支预测可能对您有利。

另一种可能性是,.NET 框架在使用 AsOrdered() 投影时针对单调递增整数 (int.Range) 的情况进行了一些优化。我不确定这将如何运作,但这是可能的。

一个有趣的比较测试是按随机顺序生成第三组数字(显然,您必须提前将它们随机化,然后处理三个数组)。那你看看跟这个有没有关系?