为什么将多线程应用程序限制为一个核心使其运行得更快?

时间:2012-09-07 15:07:19

标签: windows multithreading cpu scheduler affinity

我有一个用C ++编写的本机多线程 Win32 应用程序,该应用程序有大约3个相对繁忙的线程和4到6个没有那么多的线程。当它以正常模式运行时,在8核计算机上总CPU使用率增加约15%,应用程序在大约30秒内完成。当我通过将关联掩码设置为0x01将应用程序限制为仅一个核心时,它在23秒内完成得更快。

我猜测它与限制一个物理核心和/或某些并发内存访问问题时同步更便宜有关。

我正在运行Windows 7 x64,应用程序是32位。 CPU是Xeon X5570,具有4个内核并启用了HT。

有人能详细解释这种行为吗?为什么会发生这种情况以及如何提前预测这种行为?

更新:我想我的问题不是很清楚。我想知道为什么它在一个物理内核上变得更快,而不是为什么它在多个内核上没有超过15%。

5 个答案:

答案 0 :(得分:7)

问题非常模糊,所以只是根据典型的线程问题进行一些随机猜测。

一个显而易见的候选者是争用,线程争夺锁定并实际上运行串行而不是并行。您最终将支付线程上下文切换并且没有任何好处。这是C ++中容易遗漏的问题,CRT和C ++标准库中存在大量的低级锁定。两者最初的设计都没有考虑到线程。

在具有强大内存模型的cpu内核上常见的问题,如x86和x64,是“虚假共享”。当多个线程更新位于同一L1高速缓存行内的内存位置时,会发生这种情况。然后处理器花费大量的马力来保持核心缓存的同步。

如果程序实际上是执行绑定,您只能从多个执行核心中获益。如果内存受限,你就无法获益。如果您操作的数据不适合cpu缓存,您的机器仍然只有一个内存总线,并且它是一个强大的瓶颈。核心将停滞不前,等待总线迎头赶上。它仍被视为CPU时间,因此在cpu使用统计中不可见,但实际工作很少。

显然,你需要一个好的探查器来追逐这些问题。

答案 1 :(得分:2)

在没有说明应用程序的情况下,很难猜出导致应用程序运行缓慢的原因。如果您想进行详细分析,我们可以考虑以下因素 -

  • InterProcessor Communication :应用程序中的线程相互通信的程度。如果他们经常沟通,那么由于这种行为,你将有开销

  • 处理器缓存架构:这是另一个重要因素。您应该知道由于在不同处理器上运行的线程,处理器的缓存将如何受到影响。共享缓存会发生多大的颠簸。

  • 页面错误:由于程序的连续性,可能在单个处理器上运行会导致页面错误次数减少?

  • 锁定:锁定代码中的开销?这不应该导致减速。但除了上面提到的因素之外,这可能会增加一些开销。

  • 处理器上的NoC :当然,如果您将不同的线程分配给不同的处理器核心,并且它们正在进行通信,那么您需要知道它们正在采用的路径。他们之间是否有专门的联系?也许你应该看看这个link

  • 处理器负载:最后但并非最不重要的是,我希望您没有在其他处理器核心上运行其他任务,从而导致大量上下文切换。上下文切换通常非常昂贵。

  • 温度:您应该考虑的一个影响是,如果CPU内核正在升温,处理器时钟速度会变慢。我想,你不会有这种效果,但它也在很大程度上取决于环境温度。

答案 2 :(得分:2)

考虑到内存延迟对性能的巨大影响,这几乎肯定与缓存有关。

通过在单核上运行,第一级和第二级缓存保持特别热 - 远远超过在多核上传播时。

第三级缓存将在所有核心之间共享,因此它不会有任何不同,但它当然要慢很多,所以通过将位置移动到第一级和第二级缓存可以获得很多。

答案 3 :(得分:2)

“当它以正常模式运行时,在8核计算机上总CPU使用率增加约15%”

只有15%的使用率提示我另一种可能的解释:你的线程不做I / O吗?我的猜测是I / O操作决定了应用程序的总体时间,而不是CPU使用率。在大多数情况下,I / O密集型应用程序在I / O作业多线程时会变慢(只考虑同时复制两个文件而不是一个接一个地复制)。

答案 4 :(得分:1)

就问题而言,线程在多个内核上运行时相互通信,导致相对较慢的进程执行速度。而将线程限制为单个物理内核不需要线程之间的任何相互通信,因此进程加速。

这也可能取决于正在执行的任务:如果线程需要较少的资源,这可能是真的,否则在所有情况下将物理核心限制为一个核心可能效果不佳。