2

我正在尝试使用 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();
    }
}

我对原因的唯一猜测是对可枚举的兰特的争论(或者相反,复制它)。

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

4

1 回答 1

2

问题是 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 部分很容易工作。但是,分派给每个线程来运行谓词将产生相当大的开销。

然后,计数部分将需要 map reduce,同样,可能会产生相当大的开销。

因此,您可以加快速度的唯一方法是,如果谓词在计算上比调度谓词的开销更大,然后映射减少结果。

尝试在 Thread.Sleep 中敲击谓词...

于 2013-04-14T18:27:00.827 回答