我是怎么搞砸PLINQ的?(并行化简单/快速计算)

本文关键字:简单 并行化 计算 PLINQ | 更新日期: 2023-09-27 18:09:01

我试图使用PLINQ来加速一个简单的模拟,但我正在设法减慢它的速度,而不是(未注释的AsParallel运行更慢):

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();
    }
}

我唯一的猜测是在可枚举的rand上存在争用(或者相反,复制它)。

p。输出应该是PI的估计值。

我是怎么搞砸PLINQ的?(并行化简单/快速计算)

问题是Plinq有相当大的开销。它对于计算密集型的投影非常有用,你所拥有的不是计算密集型的。

<罢工>首先。PLinq不会并行化linq查询的GetNextPair部分。您可以尝试在该函数中放置一个断点,并打开线程窗口,检查每次哪个线程正在运行该函数。

其次,实际并行化的部分是
.Count(tuple => tuple.Item1*tuple.Item1 + tuple.Item2*tuple.Item2 <= 1d)

部分,基本上是

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

where部分将很容易工作。然而,调度每个线程来运行谓词将会有相当大的开销。

count部分将需要map reduce,同样会有相当大的开销。

所以唯一可以提高速度的方法是,如果谓词的计算强度大于调度谓词的开销,然后映射减少结果。

尝试在线程中敲打。休眠到谓词…