Matias Cicero
Matias Cicero

Reputation: 26281

Why is PLINQ slower than for loop?

Let's say I have these two methods:

public BigInteger PFactorial(int n)
{
    return Enumerable.Range(1, n)
                     .AsParallel()
                     .Select(i => (BigInteger)i)
                     .Aggregate(BigInteger.One, BigInteger.Multiply);
}

public BigInteger Factorial(int n)
{
    BigInteger result = BigInteger.One;
    for(int i = 1; i <= n; i++)
        result *= i;
    return result;
 }

The following were the results I got:

PFactorial(25000) -> 0,9897 seconds
Factorial(25000) -> 0,9252 seconds

I understand that PLINQ has some overhead because of the threads setup, but with such a big n I was expecting PLINQ to be faster.

Here is another result:

PFactorial(50000) -> 4,91035 seconds
Factorial(50000) -> 4,40056 seconds

Upvotes: 10

Views: 806

Answers (2)

M.kazem Akhgary
M.kazem Akhgary

Reputation: 19149

Parallel is not really possible with aggregate. At least i cant imagine that in my mind. Any way, You should make parallelization possible by dividing your list into chunks. Find those results. and finally multiply chunks. Here is the fast way of PLinq.

static public BigInteger PFactorial(int n)
{
    var range = Enumerable.Range(1, n).Select(x => (BigInteger) x).AsParallel();
    var lists = range.GroupBy(x => x/(n/Environment.ProcessorCount)).Select(x => x.AsEnumerable());
    var results = lists.Select(x => x.Aggregate(BigInteger.One, BigInteger.Multiply));
    var result = results.Aggregate(BigInteger.One, BigInteger.Multiply);
    return result;
}

Test

PFactorial(50000) -> 1,41 seconds
Factorial(50000) -> 2,69 seconds

Edit: As mentioned by Servy and Chatzigiannakis if you dont use seed it can perfectly use parallelization and you get pretty much same results as above (a bit faster).

return Enumerable.Range(1,n).Select(x => (BigInteger)x).AsParallel().Aggregate(BigInteger.Multiply);

Upvotes: 10

Avinash Jain
Avinash Jain

Reputation: 7616

Please do not assume that pLinQ is always faster than LinQ. PLinQ execution time based on many condition

Use PLinQ only when there are more elements and have some CPU intensive query. I'll suggest to use System.Threading.Thread.Sleep(1) in a function to emulate the CPU load as cycle delay and then call that function from LinQ and PlinQ for 10000 times. Then you can see the difference. Please find sample here

Your current function Factorial actually not doing any CPU intensive task and reason PLinQ taking more time, because it dived the query to run in multiple core and consolidate the result of individual core to single output, which take little more time then normal.

Also make sure you are using multi core processors (minimum 4 will give you good analysis)

Upvotes: 1

Related Questions