C# 使用嵌套的Parallel.For
考虑这个例子:C# 使用嵌套的Parallel.For,c#,.net-4.0,task-parallel-library,C#,.net 4.0,Task Parallel Library,考虑这个例子: var x = 0; for (var i = 0; i < 100; i++ ) { for (var a = i+1; a < 100; a++) x += 1; } 但是这不会在每次运行时打印4950。为什么?并行扩展以近乎命令式的语法帮助您创建、分配、运行和会合任务。它所不做的是注意各种线程安全性(其中之一)。您正在尝试使并行线程同时更新单个共享变量。要正确执行类似操作,必须引入锁等功能 我不知道你想做什么。我假设您的代码只是一个占
var x = 0;
for (var i = 0; i < 100; i++ )
{
for (var a = i+1; a < 100; a++)
x += 1;
}
但是这不会在每次运行时打印4950。为什么?并行扩展以近乎命令式的语法帮助您创建、分配、运行和会合任务。它所不做的是注意各种线程安全性(其中之一)。您正在尝试使并行线程同时更新单个共享变量。要正确执行类似操作,必须引入锁等功能
我不知道你想做什么。我假设您的代码只是一个占位符或实验。并行化只适用于隔离不同工作的情况;当你经常需要与共享数据会合时就不会了 作为每次锁定的替代方法,您可以将线程局部变量与锁结合使用:
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);
这是一种“正确”的方法,它不需要您锁定最终的total对象,只需要您在每个本地线程的循环结束时执行互锁操作
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
然而,让两个嵌套的并行的语句做这一点工作可能是个坏主意。有一个需要考虑的开销,如果你做的工作量如此之小,最好只做一个并行的语句,或者根本没有
我强烈建议你去下载并阅读,它非常详细地解释了为什么像这样的小型嵌套并行循环不是一个好主意。@onof,你会怎么做?parallel.For(01100,I=>parallel.For(I+1100,a=>{lock(x){x+=1;});但锁定“x”至少会破坏内部“并行”循环的目的。@在本例中,onof x是一种值类型。锁只能与引用类型一起使用。@chibacity right。他必须把它包装起来我的数据只是读取的,只有一个变量(集合),我把结果添加到其中,我不关心它们添加到这里的顺序。锁定是一种缓慢的机制吗?与简单的顺序实现相比,极端的锁定会给您带来更差的性能。考虑使用例如“代码>并行”(聚合)(< /代码>)来组合您的结果。看看,例如…@MattSmith是的,对不起,从Visual Studio复制时有点搞砸了:)会解决的
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