【问题标题】:In a nested loop, should Parallel.For be used on the outer or inner loop?在嵌套循环中,应该在外循环还是内循环上使用 Parallel.For?
【发布时间】:2012-07-30 05:02:53
【问题描述】:

我正在将一些代码从 .NET 2 转移到 4 并使用 TPL。

虽然我确定这个问题一定是在 SO 上的某个地方问过的,但我找不到。

我知道过度嵌套 TPL 任务可能会损害性能。

for (int y=0; y < h; y++)
    for (int x=0; x < w; x++)
        grid [x, y] = ((x + 1) * (y + 1));

您会将上面的外部或内部循环替换为 TPL,为什么?如果还有一层嵌套呢?

这是替换了内部循环的代码,在我的情况下它的表现更好,最多 1 秒。

int w = 10000;
int h = 10000;
int [,] grid = new int [w, h];
int [] index = new int [w * h];
DateTime time = DateTime.Now;
ParallelOptions options = new ParallelOptions();

options.MaxDegreeOfParallelism = Environment.ProcessorCount;

time = DateTime.Now;
for (int y=0; y < h; y++)
{
    Parallel.For
    (
        0,
        w,
        options,
        x =>
        {
            grid [x, y] = ((x + 1) * (y + 1));
        }
    );
}
span = DateTime.Now.Subtract(time);
Console.WriteLine("Filled in " + span.TotalSeconds.ToString() + " seconds.");

time = DateTime.Now;
for (int y=0; y < h; y++)
{
    Parallel.For
    (
        0,
        w,
        options,
        (x, state) =>
        {
            if (grid [x, y] < index.Length)
            {
                index [grid [x, y]]++;
            }
            else
            {
                state.Break();
            }
        }
    );
}
span = DateTime.Now.Subtract(time);
Console.WriteLine("Indexed in " + span.TotalSeconds.ToString() + " seconds.");

【问题讨论】:

  • @svick:我还没有分析,但是通过替换外部循环和内部循环的 2.6 秒通过代码计时出来了 3.5 秒。
  • @RaheelKhan 在这种情况下,您能否向我们展示一个重现您的测量结果的最小代码示例?尤其重要的是wh 的值。
  • @svick:上面添加了完整代码,内循环为并行。
  • @RaheelKhan 不要用DateTime 测量执行时间,而是使用StopWatch,它更准确。

标签: c# .net loops task-parallel-library


【解决方案1】:

在并行化内部循环时,您会看到更好的性能,因为rect[x,] 在内存中与rect[x+1,] 相邻,而rect[,y]rect[,y+1] 不相邻,因此并行化外部循环将导致更多的内存争用空间并减慢速度。

除了并行化外循环应该更快,因此如果您切换内循环和外循环然后在外循环上执行Parallel.For,您应该会获得比当前测试更好的性能。

另一件值得注意的事情是边界检查有点昂贵,因此您还可以通过使用不安全的代码/指针而不是循环遍历大型数组来看到一些性能提升。

【讨论】:

    【解决方案2】:

    外循环,因为使用内循环会比外循环造成更多的跨线程通信。

    【讨论】:

    • 我猜到了,但一些初步测试显示:外部:3.5 秒,内部:2.6 秒。
    【解决方案3】:

    没有! 你甚至有性能问题吗?如果您提供的代码示例是真实的,看起来您可以从jagged array 中受益,他的性能要好得多。

    【讨论】:

    • 网格是矩形的,用锯齿状阵列尝试它会增加时间。
    • 这听起来很奇怪。锯齿状数组可以更快地访问元素,尽管它们需要更多时间来分配和负担 GC。你能显示你使用的代码吗?另请注意,在锯齿状数组中,按列而不是按行遍历它的性能要高得多。这与它们在内存中的存储方式有关。如果您愿意,我可以详细说明。
    • 仅仅因为你觉得这个建议对你不合适而投反对票并不酷。
    • 我没有投反对票。无论如何,完整的代码都在上面发布。您可以轻松地将其替换为锯齿状数组并进行验证。
    • 如果它有帮助,那么投票反对的人可能会这样做,因为问题是关于 TPL 反对传统循环。无论使用哪种数组,差异都是相同的(相对的)。
    猜你喜欢
    • 2016-05-13
    • 2018-07-15
    • 2015-04-12
    • 2021-05-30
    • 2021-01-05
    • 1970-01-01
    • 2015-07-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多