双核超线程:我应该使用4个线程、3个线程还是2个线程?

15
如果同时生成多个线程(或进程),假设任务是CPU绑定的,那么生成与物理处理器数量相同还是逻辑处理器数量相同的线程更好?还是介于两者之间的某个数字(比如3个线程)更好?性能是否取决于正在执行的指令类型(比如非本地内存访问是否与缓存命中有很大不同)?如果是这样,请问在哪些情况下利用超线程会更好?
更新:我提出这个问题的原因是,我记得在某个地方读到过,如果您有与虚拟处理器数量相同的任务,那么同一物理核心上的任务有时可能会使CPU资源匮乏,并防止彼此获得所需的资源,这可能会降低性能。这就是为什么我想知道生成与虚拟核心数量相同的线程是否是一个好主意。
6个回答

5

性能取决于各种因素。大多数任务不是严格的CPU绑定,因为即使所有数据都在内存中,通常也不在处理器缓存中。我见过一些例子(比如这个),其中内存访问模式可以极大地改变给定“并行”进程的性能特征。

简而言之,并没有适用于所有情况的完美数字。


4
使用超线程技术,每个核心运行2个线程可以提高性能。看起来完全受CPU限制的作业通常并不是这样,超线程可以从偶发的中断或上下文切换中提取一些“额外”的周期。
另一方面,使用具有Turbo Boost的Core iX处理器时,最好每个核心运行1个线程以鼓励CPU自我超频。
在工作中,我们经常在全CPU下运行许多核心服务器进行各种计算数天。不久前,我们测量了有无HT的性能差异。我们发现,平均而言,使用超线程,同时运行两倍的作业,我们可以比没有超线程时更快地完成相同数量的作业约10%。
假设2×核心是一个很好的起点,但最重要的是:进行测试!

+1 感谢指出 Turbo Boost 功能... 我自己的 CPU 上有它,但我从未想过它如何影响方程式的一部分。 - user541686
1
是否能够通过超线程获得性能提升与缓存大小减半有关,这是因为如果您的缓存命中率足够高,则缓存大小的损失不会抵消(或更糟)具有两个硬件线程所带来的收益。 - user82238

2
我记得超线程技术可以提高性能高达30%。一般来说,您最好将它们视为4个不同的核心。当然,在某些特定情况下(例如,将相同的长时间运行任务绑定到每个核心),您可以更好地划分处理,考虑到某些核心仅仅是逻辑核心。
有关超线程本身的更多信息,请单击此处

+1 有趣...我之前读过其他关于超线程的英特尔文档,但这份不同且包含更多信息;谢谢! - user541686
链接现在是404。 - user643011

2
当两个线程具有类似的内存访问模式但访问不同的数据结构时,使用超线程在同一个核心上运行两个线程大致相当于在两个具有一半缓存的单独核心上运行。如果内存访问模式使得一半缓存足以防止抖动,则性能可能很好。如果内存访问模式会导致减半缓存引起抖动,可能会导致性能下降十倍(这意味着没有使用超线程可能会更好)。
另一方面,有些情况下超线程可能会带来巨大优势。如果许多线程都将使用无锁数据结构读写相同的共享数据,并且所有线程必须看到数据的一致视图,那么尝试在分离的处理器上运行线程可能会导致抖动,因为每次只有一个处理器可以同时读写任何给定的高速缓存行;将这样的线程运行在两个核心上可能需要比仅运行一个线程更长时间。然而,当一个数据被多个线程在单个核心上访问时,这种高速缓存行仲裁是不需要的。在这些情况下,超线程可能会带来巨大优势。
不幸的是,我不知道有什么方法可以给调度程序任何"提示",以建议一些线程应该尽可能分享一个核心,而其他线程应尽可能分开运行。

你可以为一个线程设置处理器亲和性,这比提示更好。 - Chris O
2
@ChrisO:是的,但一个真正的“提示”机制应该能够说“线程X应该尽可能与线程Y共享相同的核心”,同时仍然允许调度程序决定它们在任何给定时刻将共享哪个核心。 - supercat
是的,我明白了,提示文本实际上比硬编码的核心#更好。 - Chris O
1
@ChrisO:我觉得很奇怪并且恼人的是,鉴于以下三种情况:(1) 有些情况下,超线程可能比单线程快近一倍,而使用两个核心会慢很多;(2) 有些情况下,使用两个核心可能比单线程快近一倍,而超线程可能慢很多;(3) 应用程序的作者可能对应用程序是否接近以上任一极端有相当好的想法,却没有广泛的支持来指定应用程序的首选线程方案。 - supercat

1
HT允许使用额外的虚拟核心,对于大部分CPU密集型任务可提高约10-30%的性能。尽管这些任务看似CPU密集,但除非它们是自定义的汇编代码,否则通常会遭受来自RAM和本地缓存之间的IO等待。这使得在一个物理HT启用的核心上运行一个线程时,另一个线程正在等待IO。然而,这也带来了一个劣势,即两个线程共享同一缓存/总线,这将导致每个线程的资源减少,可能会导致两个线程在等待IO时暂停。
在最后一种情况下,仅运行一个线程将减少最大同时理论处理能力(约10-30%),以便运行单个线程而不会出现缓存争用的减速,这在某些应用程序中可能非常显著。
选择要使用哪些核心与选择要运行多少个线程一样重要。如果每个线程的CPU占用时间大致相同,则最好设置亲和性,使使用大多数不同资源的线程位于不同的物理核心上,并将使用公共资源的线程分组到同一物理核心(不同的虚拟核心)上,以便可以从同一缓存中使用公共资源,无需额外等待IO。

由于每个程序具有不同的CPU使用特性,缓存抖动可能会或可能不会导致主要减速(通常是这样),因此在进行分析之前无法确定理想的线程数量。最后需要注意的一点是,操作系统/内核也需要一些CPU和缓存空间。如果需要在CPU绑定的线程上实现实时延迟以避免共享缓存/CPU资源,则通常最好将单个(物理)核心保留给操作系统。如果线程经常等待IO并且缓存抖动不是问题,或者正在运行专门为应用程序设计的实时操作系统,则可以跳过此最后一步。

http://en.wikipedia.org/wiki/Thrashing_(computer_science) http://en.wikipedia.org/wiki/Processor_affinity


0

其他答案已经提供了很多优秀的信息。但是,还有一个要考虑的点是SIMD单元在同一芯片上的逻辑核之间是共享的。因此,如果您正在运行使用SSE代码的线程,您会在所有4个逻辑核心上运行它们,还是只生成2个线程(假设您有两个芯片)?对于这种奇怪的情况,最好使用您的应用程序进行分析。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接