如何在4核CPU上更快地完成相同的计算:4个线程或50个线程?

时间:2012-02-07 20:36:40

标签: multithreading parallel-processing

让我们假设我们有固定数量的计算工作,没有阻塞,睡眠,等待/等待。这项工作可以很好地并行化 - 它包含100M小型和独立的计算任务。

4核CPU的速度更快 - 运行4个线程还是......让我们说50?为什么第二种变体应该是摇摆不定的?有多少摇摆不定?

正如我所假设的:当你在4核CPU上运行4个繁重的线程而没有其他耗费CPU的进程/线程时,调度程序根本不允许在核心之间移动线程;在这种情况下,它没有理由这样做。 Core0(主CPU)将负责执行硬件计时器的中断处理程序每​​秒250次(基本Linux配置)和其他硬件中断处理程序,但另一个核心可能不会感到任何担忧。

上下文切换的成本是多少?存储和恢复CPU寄存器的时间是否适用于不同的上下文? CPU内部的缓存,管道和各种代码预测事项怎么样?我们可以说每次切换上下文时,都会损坏CPU中的缓存,管道和一些代码解码功能吗?因此,在单个内核上执行的线程越多,与串行执行相比,它们可以一起完成的工作量减少了吗?

关于多线程环境中的缓存和其他硬件优化的问题现在对我来说是个有趣的问题。

5 个答案:

答案 0 :(得分:11)

正如@Baile在评论中提到的,这是高度应用,系统,环境特定的。

因此,我不打算采用强硬的方法为每个核心提及1个线程。 (或超线程的2线程/核心)

作为一名经验丰富的共享内存程序员,我从我的经验中看到,最佳线程数(对于4核机器)的范围可以是1到64 +。

现在我将列举可能导致此范围的情况:

最佳线程<核心数量

在某些非常细粒度并行的任务(例如小FFT)中,线程的开销是主要的性能因素。在某些情况下,完全并行化没有帮助。在某些情况下,您可以通过2个线程获得加速,但是在4个线程中向后扩展。

另一个问题是资源争用。即使您具有可以轻松分割为4个内核/线程的高度可并行化的任务,您也可能会遇到内存带宽和缓存效应的瓶颈。通常,您会发现2个线程与4个线程一样快。 (好像经常出现非常大的FFT)

最佳主题=核心数

这是最佳情况。这里不需要解释 - 每个核心一个线程。大多数令人尴尬的并行应用程序不是内存或I / O绑定在这里。

最佳主题>核心数量

这是有趣的地方......非常有趣。你听说过负载不平衡吗?如何过度分解和偷工作?

许多可并行化的应用程序是不规则的 - 这意味着任务不会分成相同大小的子任务。因此,如果您最终将大型任务拆分为4个不等大小,请将它们分配给4个线程并在4个核心上运行...结果?并行性能差,因为1个线程的工作量比其他线程多10倍。

这里的常见解决方案是将任务过度分解成许多子任务。您可以为每个线程创建线程(现在您可以获得线程>> 核心)。或者您可以使用某种具有固定线程数的任务调度程序。并非所有任务都适用于两者,因此通常情况下,将任务过度分解为4核机器的8或16个线程的方法可以获得最佳结果。


虽然产生更多线程可以带来更好的负载平衡,但开销会增加。所以通常在某处有一个最佳点。我在4个核心上看到高达64个线程。但如上所述,它具有高度的应用特性。你需要进行实验。


编辑:扩大答案以更直接地回答问题......

  

上下文切换的成本是多少?存储和恢复的时间   CPU注册不同的上下文?

这非常依赖于环境 - 并且有点难以直接衡量。
简答:非常昂贵 This might be a good read.

  

内部的缓存,管道和各种代码预测内容如何?   中央处理器?我们可以说每次切换上下文时,我们都会伤害缓存,   管道和CPU中的一些代码解码工具?

简短回答:当您关闭上下文时,您可能会清空管道并弄乱所有预测变量。与缓存相同。新线程可能会用新数据替换缓存。

虽然有一个问题。在线程共享相同数据的某些应用程序中,一个线程可能会为另一个传入线程或另一个共享同一缓存的核心上的另一个线程“加热”缓存。 (虽然很少见,但我之前在我的一台NUMA机器上看到过这种情况 - 超线性加速:16核16.6倍!?!?!)

  

因此,在单个核心上执行的线程越多,他们可以做的工作就越少   与串行执行相比?

取决于,取决于...除非超线程,肯定会有开销。但我读过一篇论文,其中有人使用第二个线程来预取主线程...是的,这很疯狂......

答案 1 :(得分:0)

如果您可以使用4个线程,请使用它们。在4核机器上,50不会比4快。你得到的只是更多的开销。

当然,您正在描述理想的非现实世界情况,因此无论您实际构建什么,您都需要进行衡量,以了解性能如何受到影响。

答案 2 :(得分:0)

有超线程技术可以处理每个CPU多一个线程,但它几乎不依赖于你想要做的计算类型。考虑使用GPU或非常低的汇编语言来实现最大功率。

答案 3 :(得分:0)

创建50个线程实际上会损害性能,而不是改善它。它没有任何意义。

理想情况下,您应该制作4个线程,而不是更多,而不是更少。由于上下文切换会有一些开销,但这是不可避免的。 OS /服务/其他应用程序线程也应该被执行。但是现在拥有如此强大且照明速度快的CPU,这一点无关紧要,因为这些OS线程只需占用CPU时间的2%。在程序运行时,几乎所有这些都将处于阻塞状态。

您可能认为,由于性能至关重要,您应该使用低级汇编语言对这些小关键区域进行编码。现代编程语言允许这样做。

但严重的是......编译器以及Java的JVM将优化这些部分以至于它不值得(除非你真的想要这样做)。而不是你的计算在100秒内完成,它们将在97或98完成。你必须问自己的问题是:是否值得所有这些小时的编码和调试?

您询问了上下文切换的时间成本。这些天来,这些都非常低。看看运行Windows 7的现代双核CPU。如果您在该计算机和MySQL数据库服务器上启动Apache Web服务器,您将轻松超过800个线程。机器感觉不到。要了解这笔费用有多低,请在此处阅读:How to estimate the thread context switching overhead?。为了节省搜索/阅读部分:上下文切换可以每秒数十万次

答案 4 :(得分:0)

如果您可以将40个任务的编程转换得比操作系统更好,则4个线程会更快。