我再次努力去理解并行计算的一些事情。
在我正在处理的代码中,我有一个扩展list<list<double>>
的类。在这个类中,我正在编写一个方法来返回list<list<double>>
中值的平均值。这种方法是私有的。
public class myClass : list<list<double>>
{
//properties and stuff
private double average()
{
//method body
}
}
这个方法我有两个版本,它们都有效。第一个版本是serial:
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&GT;。这[INT]' 有一些无效的论点
我在这里不理解这个错误,因为i和j都是int类型。
然后我在Interlocked.CompareExchange(ref avg, tot+sub, tot);
上又出现了一个错误(预计,因为我真的不明白这个方法是如何工作的):
当前上下文中不存在名称“sub”
有人能指出我最后一个片段的正确形式吗?和/或一些材料来澄清这些事情?我从http://msdn.microsoft.com/en-us/library/dd460703.aspx读到,但这对我来说没有任何帮助。
答案 0 :(得分: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]
的长度相同,这不是由类型保证或建议的。
答案 1 :(得分:1)
引发第一个错误是因为i参数是long类型。这是因为存在两个类似的重载,一个具有int类型的第一个参数,另一个具有long类型。要选择“int”重载,必须显式实例化lambda表达式:
new Func<int, ParallelLoopState, double, double>((i, loop, sub) => { ... })
引起第二个错误是因为子变量在给定范围内不存在。