为什么将multithreading应用程序限制到一个内核会使其运行速度更快?

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

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

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

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

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

Solutions Collecting From Web of "为什么将multithreading应用程序限制到一个内核会使其运行速度更快?"

没有说明应用程序,只是猜测导致应用程序运行缓慢的原因是很困难的。 如果你想进行详细的分析,我们可以考虑以下因素 –

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

  • 处理器缓存架构 :这是另一个重要的因素。 您应该知道处理器的高速缓存将因为在不同处理器上运行的线程而受到影响。 共享缓存将发生多少次颠簸。

  • 页面错误 :由于程序的顺序性,也许在单个处理器上运行会导致更少的页面错误数量?

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

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

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

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

这个问题是非常模糊的,所以只是基于典型的线程问题的一些随机猜测。

一个明显的候选人是争夺,线程争夺一个锁,实际上运行串行而不是并行。 你将最终支付线程上下文切换,并没有获得任何好处。 这是一个在C ++中很容易遗漏的问题,在CRT和C ++标准库中有很多低级别的锁定。 两者最初设计时都不考虑线程。

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

如果程序实际上是执行的,你只能从多个执行内核中获益。 如果它的内存限制,你不能得到好处。 如果您操作的数据不能满足CPU高速缓存的要求,那么您的机器仍然只有一条内存总线,并且是一个强大的瓶颈。 核心只会停下来,等待公交车赶上。 它仍然算作CPU时间,所以在CPU使用统计中不会看到,但是很少有实际的工作正在完成。

显然你需要一个好的分析器来追逐这些问题。

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

通过在一个单一的核心,一级和二级缓存保持特别热 – 比多个核心传播时更是如此。

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

“当它运行在正常模式下时,总的CPU使用率在8核机器上增加了大约15%”

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

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

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