3

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

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

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

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

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

4

5 回答 5

7

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

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

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

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

显然,您需要一个好的分析器来解决这类问题。

于 2012-09-11T12:25:49.060 回答
2

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

  • InterProcessor Communication:应用程序中的线程相互通信的程度。如果他们经常交流,那么您将因这种行为而产生开销

  • 处理器缓存架构:这是另一个值得关注的重要因素。您应该知道由于在不同处理器上运行的线程将如何影响处理器的缓存。共享缓存会发生多少抖动。

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

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

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

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

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

于 2012-09-17T14:14:14.493 回答
2

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

通过在单个内核上,第一级和第二级缓存保持特别热 - 比您分布在多个内核上时更热。

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

于 2012-09-17T14:21:25.073 回答
2

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

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

于 2012-09-17T15:12:34.060 回答
1

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

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

于 2012-09-17T08:22:43.693 回答