6

誰かがこれのための正しいPlinqコードが何であるかを教えてもらえますか?二重配列の各要素の正弦の絶対値の平方根を合計していますが、Plinqは間違った結果を示しています。

このプログラムからの出力は次のとおりです。

Linqアグリゲート=75.8310477905274(正しい)Plinqアグリゲート= 38.0263653589291(本来の約半分)

私は何か間違ったことをしているに違いありませんが、私は何を理解することができません...

(これは、Core 2 Duo Windows 7x64PC上のVisualStudio2008で実行しています。)

コードは次のとおりです。

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

2 に答える 2

3

集計は、PLINQ では少し異なります。

MSDN ブログから:

アキュムレータを初期化する値を期待するのではなく、ユーザーは値を生成するファクトリ関数を提供します。

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

これで、PLINQ はスレッドごとに独立したアキュムレータを初期化できるようになりました。各スレッドが独自のアキュムレータを取得したので、フォールディング関数とアキュムレータ結合関数の両方がアキュムレータを自由に変更できます。PLINQ は、アキュムレータが複数のスレッドから同時にアクセスされないことを保証します。

したがって、あなたの場合、並列集計の出力を合計するアキュムレータ関数も渡す必要があります(したがって、本来あるべきものの約半分の結果が表示されるのはなぜですか)。

于 2009-05-13T12:06:35.077 に答える
0

MSDN ブログに感謝します。現在は正しく動作しているようです。コードを次のように変更しました。

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);
        }
    }
}
于 2009-05-13T14:59:37.697 に答える