【问题标题】:Parallel-For loop giving different sum results than single for loop. What am I missing?Parallel-For 循环给出的求和结果与单个 for 循环不同。我错过了什么?
【发布时间】:2016-01-13 06:33:18
【问题描述】:

我们的一个程序中有一个不为人知的错误。我已经将它的至少一部分缩小到这个并行for循环。

i 是一个 int[],用于测试目的,填充整数 0 - 99999。 runningTotal 很长。 lockObject 是一个新的 Object();

Parallel-For 循环在完成时似乎总是返回总数 704,982,704;单线程循环返回 4,999,950,000。

显然是线程问题,但我只是没有看到错误。 Parallel-For 循环是否正确实施?

相关代码如下:

//i int[] test ---------------------------------------------
object lockObject = new object();
int[] i = new int[100000];
for (int x = 0; x < i.Length; x++)
{
    i[x] = x;
}
long runningTotal = 0;

Parallel.For(0, i.Length,
() => 0,
(x, loopState, subtotal) =>
{
    subtotal += i[x];
    return subtotal;
},
(s) =>
{
    lock (lockObject)
    {
        runningTotal += s;
    }
}
);
runningTotal = 0;
for (int x = 0; x < i.Length; x++)
{
    runningTotal += i[x];
}

【问题讨论】:

  • 这真的很奇特。当localinit 返回 0 (Int32) 时,它会在我的测试中间歇性溢出,但如果 localinitInt64 (Parallel.For(0, i.Length, () =&gt; 0L ...),则可以可靠地工作
  • 我尝试了您的建议,是的,它现在运行良好,似乎已经解决了我们的问题。谢谢!如果您可以将其放入“响应”中,我会将其标记为答案。
  • 在我确切地知道问题发生的原因之前,这并不是我可以满意的答案。得到全面的解释后,我会进行一些挖掘并报告。
  • 我想我知道它是什么。并行worker数
  • 也许 init 必须被标记为 long,因为即使它在并行循环中,也可能只分配了 1 个任务,因此会导致事情溢出。并行度由系统的底层组件自动管理。这就是你的倾向吗?

标签: multithreading c#-4.0 task-parallel-library parallel-for


【解决方案1】:

根本原因是本地状态被声明为int,有时会溢出。

这种情况会间歇性发生,并且与Parallel.For 在手头任务中抛出的工作线程数有关。如果将 MaxDegreeOfParallelism 限制为 1,则可以可靠地发生溢出。

解决方法是将本地状态声明为long

Parallel.For(0, i.Length, () => 0L, ...)

... 那么溢出永远不会发生。除此之外,您的逻辑没有任何问题。

【讨论】:

  • 标记为答案,因为我们已经弄清楚了。感谢您的帮助和洞察力!
  • @FreeCoder24,这很有趣。感谢您对问题进行简明复制。
猜你喜欢
  • 1970-01-01
  • 2015-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多