2

我再次努力理解并行计算的一些事情。在我正在处理的代码中,我有一个扩展list<list<double>>. 在这个类中,我正在编写一个方法来返回list<list<double>>. 此方法是私有的。

public class myClass : list<list<double>>
{
    //properties and stuff
    private double average()
    {
        //method body
    }
}

我有这个方法的两个版本,它们都可以工作。第一个版本是串行的:

private double average()
{
    double avg = 0;
    for (int i = 0; i < this.Count; i++)
    {
        for (int j = 0; j < this[0].Count; j++)
        {
            avg += this[i][j];
        }
    }
    avg = avg / (this.Count*this[0].Count);
    return avg;
}

第二个版本是并行的:

private double average()
{
    double avg = 0;
    double[] cumsum = new double[this.Count];
    Parallel.For(0, this.Count, i =>
        {
            cumsum[i] = 0;
            for (int j = 0; j < this[0].Count; j++)
            {
                cumsum[i] += this[i][j];
            }
        });
    avg = cumsum.Sum() / ((this.Count * this[0].Count));
    return avg;
}

作为一个学习练习,我试图通过使用更复杂的并行线程来搞砸事情。我的想法是不使用对行求和的中间数组。具体来说,这是我的尝试(不起作用):

private double average()
{
    double avg = 0;
    Parallel.For<double>(0, this.Count, () => 0, (i, loop, sub) =>
        {
            for (int j = 0; j < this[0].Count; j++)
            {
                sub += this[i][j];
            }
            return sub;
        },
        (x) => 
            {
                double tot = avg;
                Interlocked.CompareExchange(ref avg, tot+sub, tot);
            });
    return avg / ((this.Count * this[0].Count));
}

这个片段有(至少)两个错误。它给我的第一个错误是sub += this[i][j];

'System.Collections.Generic.List>.this[int]' 的最佳重载方法匹配有一些无效参数

我在这里不明白这个错误,因为 i 和 j 都是 int 类型。

然后我有一个进一步的错误Interlocked.CompareExchange(ref avg, tot+sub, tot);(预期,因为我真的不明白这个方法是如何工作的):

当前上下文中不存在名称“sub”

有人可以指出最后一个片段的正确形式吗?和/或一些材料来澄清这些事情?我从http://msdn.microsoft.com/en-us/library/dd460703.aspx阅读,但它并没有帮助我弄清楚。

4

2 回答 2

2

就个人而言,我会使用:

double sum = yourListOfList.AsParallel().SelectMany(list => list).Average();

为了修复您的方法,您需要在本地最终 lambda 中使用您的循环状态。(您目前根本没有使用x。)

double sum = 0;
var syncObj = new object();
Parallel.For<double>(0, this.Count, () => 0, (i, loop, sub) =>
    {
        var innerList = this[i];
        for (int j = 0; j < innerList.Count; j++)
        {
            sub += innerList[j];
        }
        return sub;
    },
    (x) => 
        {
            lock(syncObj)
               sum += x;
        });
return sum / ((this.Count * this[0].Count));

请注意,您的版本(以及我的“更正”)有很多缺点。假设每个子列表的长度与 相同this[0],类型不保证或建议。

于 2013-08-13T18:32:40.100 回答
1

The first error is caused because the i argument is of the long type. This is because two similar overloads exist, one with the first parameter of the int type, another with the long type. To select the "int" overload, you have to instantiate a lambda expression explicitly:

new Func<int, ParallelLoopState, double, double>((i, loop, sub) => { ... })


The second error is caused because the sub variable doesn't exist in the given scope.

于 2013-08-13T19:04:34.217 回答