考虑一下这个例子:
var x = 0;
for (var i = 0; i < 100; i++ )
{
for (var a = i+1; a < 100; a++)
x += 1;
}当打印x时,我们总是得到4950。如果我想并行化呢?
这就是我想出来的
Parallel.For(0, 100, i => Parallel.For(i + 1, 100, a => { x += 1; }));但是,,,这并不是每次运行它时都打印4950。为什么?
发布于 2010-07-19 11:48:26
并行扩展帮助您以近乎命令式的语法创建、分配、运行和集合任务.没有做的是照顾每种类型的线程安全(陷阱之一)。您正在尝试使并行线程同时更新单个共享变量。要正确地执行这样的操作,您必须引入例如锁定。
我不知道你想做什么。我假设您的代码只是一个占位符或实验。只有当您能够隔离不同的工作片段时,并行化才适合;而不是当您必须经常与共享数据会合时。
发布于 2013-10-04 18:07:19
这是一种“正确”的方法,它不需要锁定最终的总计对象,只需要在每个本地线程的循环结束时执行互锁操作。
int x = 0;
Parallel.For(0, 100,
() => 0, //LocalInit
(i, loopstate, outerlocal) =>
{
Parallel.For(i + 1, 100,
() => 0, //LocalInit
(a, loopState, innerLocal) => { return innerLocal + 1; },
(innerLocal) => Interlocked.Add(ref outerlocal, innerLocal)); //Local Final
return outerlocal;
},
(outerLocal) => Interlocked.Add(ref x, outerLocal)); //Local Final然而,让两个嵌套的Parallel语句来完成这一点工作可能是个坏主意。有一个开销成本需要考虑,如果您正在做这么少的工作,最好只做一个Parallel语句,或者根本没有。
我强烈建议您下载并阅读并行编程模式,它详细介绍了为什么像这样的小型嵌套并行循环不是一个好主意。
发布于 2010-07-19 12:12:31
作为每次锁定的替代方法,您可以结合使用线程局部变量和锁:
Object thisLock = new Object();
var globalSum = 0;
System.Threading.Tasks.Parallel.For(0, 100, i => {
System.Threading.Tasks.Parallel.For(i + 1, 100, () => 0, (num, loopState, subSum) => ++subSum, subSum => {
lock(thisLock) { globalSum += subSum; }
});
});
Console.WriteLine(globalSum);https://stackoverflow.com/questions/3280688
复制相似问题