2013-04-14 39 views
2

我试图使用PLINQ加快一个简单的模拟,但我设法慢下来,而不是(未注释进行AsParallel运行速度较慢):我该如何篡改PLINQ? (并行化简单/快速计算)

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的估计值。

+2

如果您填写一个数组,用它来代替GetNextPair(),这有多大差别?由于收益可能会缓冲。 –

+0

你到底在做什么?我看不到任何AsParallel() – Aron

+0

@Aron你看不到行///。AsParallel()'? – svick

回答

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

的其中一部分将会很容易的工作。但是,调度到每个线程来运行谓词将会有相当的开销。

然后,计数部分将需要一个映射减少,可能会有相当的开销。

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

尝试在Thread.sleep代码重击到谓语...

+0

,你说得很对 - 谓词中的Thread.Sleep()表示它。然而,GetNextPair()方法被许多工作线程调用(这肯定会让我感觉更好)。 –

+0

@ nik.shornikov编辑以反映这个:) – Aron

+2

@ nik.shornikov即使它是从多个线程中调用的,也不会从多个线程*同时调用*,因此部分查询不会被并行化。 – svick