Question

I'm trying to use PLINQ to speed up a simple simulation, but I'm managing to slow it down instead (uncommented AsParallel runs slower):

class Program
{
    private static readonly Random Random = new Random();

    private static IEnumerable<Tuple<double, double>> GetNextPair(int pairs)
    {
        for (int i = 0; i < pairs; i++)
            yield return new Tuple<double, double>(Random.NextDouble(), Random.NextDouble());
    }

    private static double RunSimPlinq(int count)
    {
        return
            GetNextPair(count)
                //.ToArray()
                //.AsParallel()
                .Count(tuple =>
                    {
                        //Thread.Sleep(10);
                        return tuple.Item1*tuple.Item1 + tuple.Item2*tuple.Item2 <= 1d;
                    })*4d/count;
    }

    static void Main()
    {
        Stopwatch sw = new Stopwatch();
        sw.Start();
        Console.WriteLine(RunSimPlinq(100));
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);
        Console.Read();
    }
}

My only guess as to the reason is contention on the enumerable of rands (or, on the contrary, copying of it).

PS. The output should be an estimate of PI.

Was it helpful?

Solution

The issue is that Plinq has quite a large amount of overhead. Its very useful for computationally intensive projections, what you have IS NOT computationally intensive.

Firstly. PLinq will NOT parallelize the GetNextPair part of the linq query. You can try placing a break point into that function and bringing up the Thread window to check which thread is running it each time.

Secondly the part that IS actually parallelised is the

.Count(tuple => tuple.Item1*tuple.Item1 + tuple.Item2*tuple.Item2 <= 1d)

part, which is basically

.Where(tuple => tuple.Item1*tuple.Item1 + tuple.Item2*tuple.Item2 <= 1d)
.Count()

The where part is going to work quite easily. However, the dispatching to each thread to run the predicate is going to have quite an overhead.

The count part then would require a map reduce, again, could have quite an overhead.

So the only way you could have a speed up is if the predicate is computationally more intensive than the overhead of scheduling the predicate and then map reducing the result.

Try whacking in a Thread.Sleep into the predicate...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top