2009-05-13 10 views
6

Czy ktoś może mi powiedzieć, jaki jest poprawny kod Plinq? Sumuję pierwiastek kwadratowy z bezwzględnej wartości sinusa każdego elementu dla podwójnej tablicy, ale Plinq daje mi zły wynik.Plinq daje inne wyniki od Linq - co robię źle?

Wyjście z tego programu jest:

LINQ łączna = 75,8310477905274 (poprawne) Plinq łączna = +38,0263653589291 (około połowa tego, co powinno być)

muszę robić coś złego, ale nie mogę pracy, co ...

(biegnę to z Visual Studio 2008 na Core 2 Duo systemu Windows 7 x64 PC.)

Oto kod:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Collections; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main() 
     { 
      double[] array = new double[100]; 

      for (int i = 0; i < array.Length; ++i) 
      { 
       array[i] = i; 
      } 

      double sum1 = array.Aggregate((total, current) => total + Math.Sqrt(Math.Abs(Math.Sin(current)))); 
      Console.WriteLine("Linq aggregate = " + sum1); 

      IParallelEnumerable<double> parray = array.AsParallel<double>(); 
      double sum2 = parray.Aggregate((total, current) => total + Math.Sqrt(Math.Abs(Math.Sin(current)))); 
      Console.WriteLine("Plinq aggregate = " + sum2); 
     } 
    } 
} 

Odpowiedz

3

Agregat działa nieco inaczej w PLINQ.

Od MSDN Blogs:

niż oczekiwano wartość zainicjować akumulator aby użytkownik daje nam funkcję fabrycznego że generuje wartość:

public static double Average(this IEnumerable<int> source) 
{ 
    return source.AsParallel().Aggregate(
     () => new double[2], 
     (acc, elem) => { acc[0] += elem; acc[1]++; return acc; }, 
     (acc1, acc2) => { acc1[0] += acc2[0]; acc1[1] += acc2[1]; return acc1; }, 
     acc => acc[0]/acc[1]); 
} 

teraz , PLINQ może zainicjować niezależny akumulator dla każdego wątek. Teraz, gdy każdy wątek otrzymuje swój własny akumulator, zarówno składana funkcja , jak i funkcja akumulatora, która łączy funkcję , mogą dowolnie modyfikować akumulatory . PLINQ gwarantuje, że akumulatory nie będą dostępne jednocześnie z wielu wątków.

Tak więc, w twoim przypadku, musisz również przekazać funkcję akumulatora, która sumuje wyjścia równoległych agregatów (stąd dlaczego widzisz wynik, który jest mniej więcej połową tego, co powinno być).

0

Dziękuję Blogi MSDN. Wygląda na to, że działa prawidłowo. Zmieniłem kod w następujący sposób:

using System; 
using System.Linq; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main() 
     { 
      Test(); 
     } 

     static void Test() 
     { 
      double[] array = new double[100]; 

      for (int i = 0; i < array.Length; ++i) 
      { 
       array[i] = i; 
      } 

      double sum1 = array.Aggregate((total, current) => total + Math.Sqrt(Math.Abs(Math.Sin(current)))); 
      Console.WriteLine("Linq aggregate = " + sum1); 

      IParallelEnumerable<double> parray = array.AsParallel(); 

      double sum2 = parray.Aggregate 
      (
       0.0, 
       (total1, current1) => total1 + Math.Sqrt(Math.Abs(Math.Sin(current1))), 
       (total2, current2) => total2 + current2, 
       acc => acc 
      ); 

      Console.WriteLine("Plinq aggregate = " + sum2); 
     } 
    } 
} 
Powiązane problemy