为什么将多线程应用程序限制在一个核心会使其运行速度更快



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

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

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

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

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

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

一个明显的候选者是争用,线程争夺锁,实际上是串行运行而不是并行运行。您最终将为线程上下文切换付费,却得不到任何好处。这是C++中很容易忽略的问题,CRT和C++标准库中有很多低级锁定。两者最初都是在不考虑螺纹的情况下设计的。

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

只有当程序实际受执行约束时,才能从多个执行核心中获得好处。如果它的内存受限,你就无法获得好处。您的机器仍然只有一条内存总线,如果您操作的数据无法容纳cpu缓存,这将是一个强大的瓶颈。核心将简单地停滞,等待总线赶上。它仍然被计算为cpu时间,因此在cpu使用统计数据中不可见,但实际工作几乎没有完成。

很明显,您需要一个好的探查器来解决这类问题。

如果不说明应用程序,很难猜测是什么导致了应用程序运行缓慢。如果你想进行详细的分析,我们可以考虑以下因素-

  • 处理器间通信:应用程序中线程之间的通信量。如果他们经常通信,那么的这种行为会给你带来开销

  • 处理器缓存体系结构:这是另一个重要因素。您应该知道由于线程在不同的处理器上运行,处理器的缓存将如何受到影响。在共享缓存中将发生多少抖动。

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

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

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

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

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

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

通过在单个核心上,一级和二级缓存会保持特别热,这比在多个核心上扩展时要热得多。

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

"当它在正常模式下运行时,8核机器上的总CPU使用量加起来约为15%"

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

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

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

相关内容

最新更新