Why is PLINQ slower than LINQ for this code?
Firstly, I am running this on a 2.66GHz dual core processor. I'm not sure if I have a .AsParallel () call in the correct place. I also tried it directly on the range variable and it was even slower. I do not understand why...
Here are my results:
Non-parallel process 1000 took 146 milliseconds
Parallel 1000 process took 156 milliseconds
Non-parallel process 5000 took 5187 milliseconds
Parallel 5000 process took 5300 milliseconds
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace DemoConsoleApp
{
internal class Program
{
private static void Main()
{
ReportOnTimedProcess(
() => GetIntegerCombinations(),
"non-parallel 1000");
ReportOnTimedProcess(
() => GetIntegerCombinations(runAsParallel: true),
"parallel 1000");
ReportOnTimedProcess(
() => GetIntegerCombinations(5000),
"non-parallel 5000");
ReportOnTimedProcess(
() => GetIntegerCombinations(5000, true),
"parallel 5000");
Console.Read();
}
private static List<Tuple<int, int>> GetIntegerCombinations(
int iterationCount = 1000, bool runAsParallel = false)
{
IEnumerable<int> range = Enumerable.Range(1, iterationCount);
IEnumerable<Tuple<int, int>> integerCombinations =
from x in range
from y in range
select new Tuple<int, int>(x, y);
return runAsParallel
? integerCombinations.AsParallel().ToList()
: integerCombinations.ToList();
}
private static void ReportOnTimedProcess(
Action process, string processName)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
process();
stopwatch.Stop();
Console.WriteLine("Process {0} took {1} milliseconds",
processName, stopwatch.ElapsedMilliseconds);
}
}
}
source to share
It's a little slower because PLINQ has a certain overhead (threads, scheduling, etc.), so you need to carefully choose what you will be parallelizing. This particular code you are comparing is not worth parallelizing, you must parallelize heavy-load tasks or the overhead will weigh more than the benefits of parallelizing.
source to share
Most of your runtime here will probably actually be created in a list using a method ToList()
. This will have to do multiple memory allocations, list resizing, etc. You also don't get much benefit from parallelization here, because the final operation must be synchronized (you create a single list in the output).
Try to do something significantly more complicated / expensive in the parallel segment, such as primary factorization and increasing the number of iterations to hundreds of thousands (5000 is a very small number to use when profiling). You should start to see the difference.
Also make sure you are profiling in release mode; all too often I see profiling attempts in debug mode and the results are not accurate.
source to share