Your 'Problem' is using PLINQ when it doesn't make sense
PLINQ won't always be faster.
PLINQ will ALWAYS add overhead.
In terms of CPU instructions; whatever amount of work you need to do (call it X) you will end up executing more than X instructions. PLINQ is going to do a lot of extra work kicking off threads, delegating work to them and getting the results back into a form you can work with.
The advantage to doing this is you can have more than one CPU/Core doing work. Sometimes it is faster. When the amount of CPU work you are doing is small relative to the overhead, it will be slower.
When I run your code I get the following output:
Sequential Execution 2 milliseconds
Parallel Execution 40 milliseconds
I can also see eight worker threads being created by the PLINQ code. Those eight threads represent a lot of overhead for 2 milliseconds worth of computation. You can get a feel for how much overhead it is by running your Parallel Execution benchmark twice. The worker threads will hang around. Here's my output with running it a second time:
Sequential Execution 2 milliseconds
Parallel #1 Execution 40 milliseconds
Parallel #2 Execution 3 milliseconds
The second time is much faster; but still slower than not doing anything. Because, even with the worker threads already created - PLINQ still has to do work to divide up the operations between the threads and get the results back in a format you can access.
The more work you have to do, the less impact the overhead will be. In this example, I've replaced your Where lambda with a static function called IsValid
and I compute the %2 500 times instead of only once.
static bool IsValid(int input)
{
int result=0;
for(int i =0;i<500;i++)
result = input%2;
return result == 0;
}
Now - my execution times are:
Sequential Execution 36 milliseconds
Parallel #1 Execution 47 milliseconds
Parallel #2 Execution 9 milliseconds
You can see that PLINQ is still slower on the first execution - but significantly faster on the second. If you up CPU work by increasing the loop from 500 to 5000 (on my machine) PLINQ wins, hands down.
TL;DR - You are doing right; you just aren't doing enough work to make PLINQ the faster choice.
Here's the entire source code for what I've done:
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
int[] vals = Enumerable.Range(0, Int16.MaxValue).ToArray();
sw.Start();
int[] x1 = vals.Where(IsValid).ToArray();
sw.Stop();
Console.WriteLine("Sequential Execution {0} milliseconds", sw.ElapsedMilliseconds);
sw.Restart();
int[] x2 = vals.AsParallel().Where(IsValid).ToArray();
sw.Stop();
Console.WriteLine("Parallel #1 Execution {0} milliseconds", sw.ElapsedMilliseconds);
sw.Restart();
int[] x3 = vals.AsParallel().Where(IsValid).ToArray();
sw.Stop();
Console.WriteLine("Parallel #2 Execution {0} milliseconds", sw.ElapsedMilliseconds);
Console.Read();
}
static bool IsValid(int input)
{
int result=0;
for(int i =0;i<5000;i++)
result = input%2;
return result == 0;
}