c#中使用Parallel.For的锁的意外行为
本文关键字:意外 For Parallel | 更新日期: 2023-09-27 18:02:31
执行以下操作
static object aggLock = new object();
static long max = 10000000;
static void Main(string[] args)
{
double totalSumSeq = 0;
double totalSumLock = 0;
// Seq
for (int i = 0; i < max; i++)
{
double y = Math.Sqrt(i);
totalSumSeq += y;
}
...
}
返回预期的21,081,849,486.4393。
使用 // Parallel.For(from, to, init, body, finally);
Parallel.For(0, max, () => 0.0, (i, pls, y) => // (LoopVariable, ParallelLoopState, ThreadLocalVariable)
{
y = Math.Sqrt(i);
return y;
},
partSum =>
{
lock (aggLock)
{
totalSumLock += partSum;
}
}
);
相反,我得到完全不同的值,就像在竞态条件中一样。为什么?
在返回迭代值时应该将部分和聚合:
Parallel.For(0, max, () => 0.0, (i, pls, y) =>
{
//y = Math.Sqrt(i);
int r = y + Math.Sqrt(i); // a + to fix it
return r;
}, ...
y
与() => 0.0
一起初始化为0.0,在分区的末尾重新出现为partSum
。但是您只使用了分区的最后一个值。
使用PLinq的替代方法(但是Range()不接受long
作为max):
double plinqSum = Enumerable
.Range(0, (int) max)
.AsParallel()
.Sum(i => Math.Sqrt(i)); // or just .Sum(Math.Sqrt);
这个.AsParallel().Sum()
位实际上就是你用Parallel.For()
构建的