【问题标题】:Can Parallel.For be optimized for very short-running operations?Parallel.For 能否针对运行时间非常短的操作进行优化?
【发布时间】:2012-09-20 15:37:53
【问题描述】:

我知道一些任务可以为短期运行的任务提供细粒度的控制,但我有一种情况,使用 foreach 循环更自然。问题是,是否可以告诉 Parallel.For 期待短期运行的操作并使用尽可能多的线程来最大限度地利用 CPU?

如果不是,那么您建议使用什么方法进行并行化:

bool [,] grid = new bool [1000, 1000];
for (int y=0; y<1000; y++)
    for (int x=0; x<1000; x++)
        // Ignore the bounds error. This is just to illustrate a very short operation.
        grid[x, y] |= grid[x-1, y+1];

【问题讨论】:

  • 你的 CPU 容量只有这么多。并行做事并不会神奇地从某个未知来源获得额外的处理能力。如果以串行方式运行它会使处理器最大化,那么并行运行它不会获得任何好处,实际上由于线程和上下文切换的开销,可能会减慢操作。您真正可以获得的唯一方法是,如果您的短操作是某种不受 CPU 限制的 high IO-wait 操作。所以你能告诉我们更多关于你的实际操作吗?
  • 例如,您可以将矩阵分成 4 块并运行 4 个线程。 (当然边界应该分开处理)
  • 如果有一堆短时间运行的线程,Parallel.For 将有效地进行优化。您可以使用 ParallelOptions 覆盖它:Parallel.For(1, 10, new ParallelOptions {MaxDegreeOfParallelism = Environment.ProcessorCount*2}, i =&gt; { /* TODO something with i */ }); 但这可能会对性能产生负面影响,而不是正面影响。
  • @PeterRitchie:是的,超过ProcessorCount 几乎肯定会对非 I/O 操作产生负面影响。您的ProcessorCount*2 示例在某些情况下可能会证明是有益的,因为它启用了超线程和小型、不可并行化的操作。

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


【解决方案1】:

问题是,是否有可能告诉 Parallel.For 期待短期运行的操作并使用尽可能多的线程来最大限度地利用 CPU?

是的,您可以通过创建Partitioner&lt;T&gt; 并自己处理分区来做到这一点。详情请见How to: Speed Up Small Loop Bodies

但是,在您的情况下,最好只并行化外部循环,并将内部循环顺序留在每个外部 Parallel.For 循环体内部。这将为每个工作项提供足够的指令,使其可能充分使用处理器。

话虽如此,在这种情况下 .NET 可能无法使用 Parallel.For 做得很好 - 至少在没有一些额外工作的情况下不会。通过将值并行分配给相同的数组,由于隐式数组边界检查,您将引入false sharing,它从同一位置读取(就在数组开始之前) .

有多种方法可以解决这个问题 - 例如,一种选择可能是从多维数组切换到锯齿数组。通过正确的索引和循环,这可以减少对“共享”数组的写入次数。另一种选择是使用不安全的代码和指针而不是直接访问数组,因为这样可以避免边界检查,但需要非常仔细的编码。

【讨论】:

  • 与任何性能优化一样,请确保在从更简单的实现更改代码之前测量。例如,我看到人们在没有运行时边界检查的情况下使代码复杂化以避免这种情况(因为静态分析表明不需要它:)blogs.msdn.com/b/clrcodegeneration/archive/2009/08/13/…
  • @JamesManning:是的,我同意。在这种情况下,虽然我将创建和测量多个实现,因为应用程序的这一部分是时间关键的。
  • @Reed:无论如何我都会尝试所有方法。我是分区的新手,虽然我已经阅读了你的例子,但你能用外行的术语详细说明这个概念吗?我试图了解它“如何”是有益的(不一定适合我的情况)。与默认分区相比,自定义分区可能受益的示例场景。
  • @RaheelKhan 基本上,通过自己处理分区,您可以使“小主体”成为更大的主体。它允许您将许多元素“组合”成一个元素,从而减少线程的相对开销。
猜你喜欢
  • 1970-01-01
  • 2015-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-25
  • 2013-09-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多