并行ForEach在不同的情况下给出不同的结果

时间:2016-08-12 07:22:00

标签: c# parallel-processing

我从未使用Parallel.ForEach,但我玩过它并发现了这种情况。

我运行一个并行循环(msdn https://msdn.microsoft.com/en-us/library/dd997393(v=vs.110).aspx上的代码使用subtotal *=2编辑它以尝试理解它在做什么),首先使用可枚举范围(0,1)然后{{ 1}}然后我再次运行第二个但是在线程休眠200毫秒之后,结果则不同

如果(0,1,2)没有被注释掉,这就是结果

Thread.sleep(200)

如果result 1 = 2 result 2 = 6 result 3 = 4 被注释掉,这就是结果

Thread.sleep(200)

这是代码

result 1 = 2 
result 2 = 6
result 3 = 6

我认为它与线程相互作用有关,但这似乎是一个bug

注意我确实看过Simulation gives different result with normal for loop Vs Parallel For
为什么会这样?

1 个答案:

答案 0 :(得分:3)

因为这段代码定义不明确:

 Parallel.ForEach<int, long>(nums,() => 0,(j, loop, subtotal) =>
 {
   subtotal += 1;
   subtotal *= 2;
   return subtotal;
 },(finalResult) => Interlocked.Add(ref total, finalResult));

在那里,如果单个线程执行两次迭代,那么你得到结果6.实际上,你做了:

subTotal = 0; //From init
subTotal += 1; //=1 First iteration
subTotal *= 2; //=2 First iteration
subTotal += 1; //=3 Second iteration
subTotal *= 2; //=6 Second iteration
total += subTotal; //=6 End gathering (actually interlocked)

但是如果两个线程共享工作,那么你得到

subTotal1 = 0; //From init
subTotal2 = 0; //From init
subTotal2 += 1; //=1
subTotal1 += 1; //=1
subTotal1 *= 2; //=2
subTotal2 *= 2; //=2
total += subTotal1 //=2 End gathering 1 (interlocked)
total += subTotal2 //=4 End gathering 2 (interlocked)