5

我的算法中有一个方法可以在非常大的数据集上运行非常紧密的循环。我最初是单线程写的,这很好,但是花了很长时间。我现在想要加快速度,所以我现在使用 ThreadPool 来并行化工作。问题是这会导致我的 CPU 使用率达到 95-100%,这是我所预料的。然而,我的表现已经显着提高,但我认为如果我可以减少所有上下文切换,我可以做得更好。这也导致我的其他程序有点滞后,因为它们必须与线程争夺 CPU 资源。

我的问题是我应该怎么做?我唯一能想到的就是限制一次运行的线程数,但这可能会使我的算法变慢,因为一次只能运行几个线程。我也不想在我的线程中添加睡眠,因为我只需要算法尽快运行完成。

编辑:有几个人提到使用 TPL。我认为这是一个好主意,但不幸的是,我忘了提到我一直在使用 .NET 3.5,因为父应用程序尚未发布使用 .NET 4 的版本。

4

2 回答 2

6

这都是关于资源管理的。您的程序当前占用了所有资源,因此其他程序对它们的访问权限减少。您需要平衡“我只需要算法尽快完成”部分与“这也导致我的其他程序有点滞后,因为它们必须与线程争夺 CPU 资源”。它们是相互排斥的;您不能让您的应用程序在特定机器上尽可能快地运行,同时也让其他应用程序保持完美响应。CPU在任何时间段内可以做的事情都是有限度的。

就效率提升而言,您可以做一些事情:

  • 不要将 ThreadPool 用于超优化的线程算法。ThreadPool 非常适合简单的“开始执行此操作,让我知道您已完成”操作。但是,如果您希望进行优化,则可以避免使用 ThreadPool 添加额外级别的线程调度所固有的开销(在 CPU 和操作系统固有的开销之上)。您还可以对 ThreadPool 中的线程进行更有限的控制,这意味着诸如分配处理器亲和性(负载平衡)和优先级(给线程更多或更少的时间)之类的优化不可用。尝试创建简单的线程,或者查看 TPL,它有许多策略来完成多项任务(并非所有这些都首先需要线程)。

  • 是的,您将希望能够“限制”线程数。这既是通过减少程序对它的需求来允许其他程序一些 CPU 时间,但正如我所说,多线程也存在固有的开销。经验法则是,如果 CPU 具有两倍以上的主动运行线程数,因为它具有“执行单元”(这些是 CPU 芯片上的物理内核,以及像超线程技术那样拆分一个内核的“逻辑处理器”)成两个),那么操作系统将花费更多的时间来调度线程并在它们之间切换(“缓存抖动”),而不是实际运行线程所花费的时间。更一般地说,存在收益递减规律,这将发展为“规模不经济”;最终,添加另一个线程将导致您的程序运行得比您没有使用该线程时更慢。是的,ThreadPool 可以为您处理最大线程数,但这可能是在您自己的算法中实现的各种功能中最简单的一个。

  • 确保每个线程的工作都经过优化。寻找幼稚或低效的算法(我称它们为“ O(我的上帝)-复杂性”)并简化它们。大多数操作的效率都有一个下限(因操作类型而异),“过早优化是万恶之源”(不要以牺牲代码实际工作为代价来优化性能),但是了解在多线程环境中,您在运行一次算法时可以提高算法效率的任何收益都将乘以您运行它的次数,因此确保并行操作的效率是双重好处。

于 2012-04-13T15:15:46.783 回答
2

如果您可以将您的主应用程序重写为一个foreach循环,IEnumerable您可以使用PLINQ来并行化您的循环。您可以使用WithDegreeOfParallelism来控制您的应用程序将使用多少个内核。您可以通过不使用计算机上的所有内核来防止您遇到的一些“滞后”。此外,您不必处理如何跨线程划分循环以避免不必要的资源争用。PLINQ 为您完成所有这些工作。

假设你有这个非常简单的单线程循环:

var arrayOfStuff = new[] { ... };
for (var i = 0; i < arrayOfStuff.Length; ++i)
  DoSomething(arrayOfStuff[i]);

如果订购无关紧要,您可以使用 PLINQ 并行化它,使用的核心少于可用核心:

var cores = Math.Max(1, Environment.ProcessorCount - 1);
arrayOfStuff.AsParallel().WithDegreeOfParallelism(cores).ForAll(DoSomething);

即使您的主循环更复杂,您也可以将其重写为一个迭代器块,然后您可以并行化:

IEnumerable<Stuff> GetStuff() {
  for ( ... very complex looping ... ) {
    ...
    yield return stuff;
  }
}
于 2012-04-13T15:15:01.297 回答