6

谁能告诉我正确的 Plinq 代码是什么?我将双精度数组的每个元素的正弦绝对值的平方根相加,但 Plinq 给了我错误的结果。

该程序的输出是:

Linq 聚合 = 75.8310477905274(正确) Plinq 聚合 = 38.0263653589291(大约应该是一半)

我一定是做错了什么,但我不知道是什么...

(我在 Core 2 Duo Windows 7 x64 PC 上使用 Visual Studio 2008 运行它。)

这是代码:

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 回答