I wrote some basic sample code to familiarise myself with 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.
The MSDN documentation states that adding AsOrdered() will preserve the order of the call at the possible cost of performance.
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. I am getting about 18 seconds for the ordered one and 22 seconds for the unordered one. 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.
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:
// 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?
DateTime
is not very good for performance measurements, usingStopWatch
is better. – Mogul