简体   繁体   English

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

[英]Why is my AsOrdered PLINQ query faster than my unordered one

I wrote some basic sample code to familiarise myself with PLINQ. 我写了一些基本的示例代码来熟悉PLINQ。

I came across something weird. 我遇到了一些奇怪的东西。 I don't know if it's an error in my code or an error in my understanding of PLINQ. 我不知道我的代码中是错误还是我对PLINQ的理解错误。

The MSDN documentation states that adding AsOrdered() will preserve the order of the call at the possible cost of performance. MSDN文档指出,添加AsOrdered()将以可能的性能成本保留调用的顺序。

I wrote some unit tests and noticed the effect on the order on the result set as stated in the documentation. 我写了一些单元测试,并注意到文档中所述的对结果集的顺序的影响。 But I have seen the inverse effect on performance. 但我已经看到了对性能的负面影响。

Here are both my method: 这是我的方法:

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;
}

And my very simple benchmarks 而我非常简单的基准测试

    [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);
    }

No matter how often I run this test, the ordered version beats out the unordered one. 无论我多久运行一次这个测试,有序版本都会打败无序版本。 I get about 4 seconds quicker for the ordered one on my quad core computer. 我的四核计算机上的订购速度大约快4秒。 I am getting about 18 seconds for the ordered one and 22 seconds for the unordered one. 对于有序的一个,我得到大约18秒,对于无序的一个,我得到22秒。 I have run the tests dozens of time over the course of two days (with reboots between those days). 我在两天的时间内完成了几十次测试(在那些日子之间重新启动)。

If I lower the number 10 000 000 to 6 000 000, the differences is still there but less noticeable and if I lower it to 3 000 000, it is about the same speed. 如果我将数字10 000 000减少到6 000 000,差异仍然存在,但不太明显,如果我把它降低到3 000 000,它的速度大致相同。

I tried running the tests in both order of execution and the results are the same. 我尝试按执行顺序运行测试,结果是一样的。

Here is the IsPrime method that gets called in the PLINQ query: 以下是在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;
}

What explains this? 这解释了什么?

Do You Always Run The Tests In The Same Order? 你总是以同样的顺序运行测试吗?

I've recreated your results on my machine and I found that, no matter, the 'Ordered' results were faster. 我在我的机器上重新创建了你的结果,我发现,无论如何,'Ordered'结果更快。 I used slightly modified code for benchmarking: 我使用略微修改的代码进行基准测试:

static void Main(string[] args)
{
    const int size = 9000000;
    BenchIt("Parallel", ParallelCalculatePrimesUpTo, size);
    BenchIt("Ordered ", OrderedParallelCalculatePrimesUpTo, size);
    Console.ReadKey();
}

public static void BenchIt(string desc, Func<int, IEnumerable<int>> myFunc, int size)
{
    var sw = new Stopwatch();            
    sw.Restart();
    myFunc.Invoke(size).ToList();
    sw.Stop();
    Console.WriteLine("{0} {1}",desc, sw.Elapsed);
}

My results showed, initially, that you were correct. 我的结果最初表明你是对的。 The ordered method was faster. 有序的方法更快。 However, if I SWAPPED the order of the calls, I found that the non-ordered method was faster. 但是,如果我SWAPPED调用的顺序,我发现非有序方法更快。 In other words, whichever one went second was faster. 换句话说,无论哪一个更快。 Presumably, because of the thread-pool management that the Task Parallel Library is doing. 据推测,由于任务并行库正在进行的线程池管理。

But - the differences between the two on my machine were very small. 但是 - 我机器上两者之间的差异非常小。 Nowhere near the amount of difference you saw. 你看到的差异不大。

What's Your Hardware Look Like? 你的硬件是什么样的?

PLINQ does some guessing about how to execute the fastest. PLINQ做了一些关于如何执行最快的猜测。 I don't know if this will directly help you in this case; 在这种情况下,我不知道这是否会直接帮助你; but you might want to set a break point in the middle of IsPrime and stop on it after a few hundred iterations and examine the thread window. 但是你可能想在IsPrime中间设置一个断点并在几百次迭代后停止它并检查线程窗口。

How many threads do you have when executing ParallelCalculatedPrimesUpTo verse OrderedParallelCalculatePrimesUpTo ? 执行ParallelCalculatedPrimesUpTo OrderedParallelCalculatePrimesUpTo时有多少个线程? I'm reaching here; 我到了这里; but it's possible that it's deciding on different values on your machine that creates the unexpected times you are seeing. 但它可能会决定您机器上的不同值,从而产生您所看到的意外时间。 On my machine - I get eight threads, each time - but my times are NEARLY identical - whichever one is called first is slower because of the creation of those threads. 在我的机器上 - 我每次都得到8个线程 - 但我的时间几乎完全相同 - 无论哪个被称为第一个都因为这些线程的创建而变慢。 But you aren't guaranteed a particular number of threads (you can set the maximum, but you can't force them to be used). 但是你不能保证特定数量的线程(你可以设置最大值,但不能强制它们被使用)。

Can you tell us what the CPU utilization is across the 4 different cores? 您能告诉我们4个不同内核的CPU利用率是多少? It's possible that AsOrdered() is forcing more sequential calls to happen on the same core. AsOrdered()可能会强制在同一个核心上发生更多顺序调用。 With improved locality, silicon-level caching and branch prediction may be working in your favor. 通过改进的局部性,硅级缓存和分支预测可能对您有利。

Another possibility is that there's some optimization in the .NET framework for the case of monotonically increasing integers (int.Range) when using the AsOrdered() projection. 另一种可能性是,在使用AsOrdered()投影时,对于单调递增整数(int.Range)的情况,.NET框架中有一些优化。 I'm not sure how that would work, but it's possible. 我不确定这是怎么回事,但这是可能的。

An interesting test for comparison would be to generate a third set of numbers, in random order (obviously, you'd have to randomize them ahead of time and then work off three arrays). 一个有趣的比较测试是以随机顺序生成第三组数字(显然,你必须提前随机化它们然后处理三个数组)。 Then see if that has anything to do with it? 然后看看它是否与它有关?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM