每个核心的最佳线程数

时间:2009-11-11 22:19:10

标签: parallel-processing cpu

假设我有一个4核CPU,我想在最短的时间内运行一些进程。这个过程理想上是可并行化的,所以我可以在无限数量的线程上运行它,每个线程花费相同的时间。

由于我有4个内核,我不希望通过运行比内核更多的线程来加速,因为单个内核只能在给定时刻运行单个线程。我对硬件知之甚少,所以这只是猜测。

在比线程更多的线程上运行可并行化的进程有什么好处?换句话说,如果我使用4000个线程而不是4个线程运行它,我的进程会更快,更慢,还是在大约相同的时间内完成?

13 个答案:

答案 0 :(得分:234)

如果您的线程不进行I / O,同步等操作,并且没有其他任何操作,则每个内核1个线程将为您提供最佳性能。然而,很可能并非如此。添加更多线程通常会有所帮助,但在某些时候,它们会导致性能下降。

不久前,我正在使用Mono上运行ASP.NET应用程序的2个四核机器上进行性能测试。我们使用了最小和最大线程数,最后我们发现对于该特定配置中的特定应用程序,最佳吞吐量介于36到40个线程之间。超出这些界限的任何事情表现都更糟学过的知识?如果我是你,我将测试不同数量的线程,直到找到适合您应用的数字。

有一件事是肯定的:4k线程需要更长时间。这是很多上下文切换。

答案 1 :(得分:121)

我同意@ Gonzalo的回答。我有一个不做I / O的过程,这是我发现的:

enter image description here

请注意,所有线程都在一个数组上工作,但是不同的范围(两个线程不访问相同的索引),因此如果它们在不同的数组上工作,结果可能会有所不同。

1.86机器是带有SSD的macbook air。另一台mac是带普通硬盘的iMac(我认为是7200转)。 Windows机器也有一个7200转的硬盘。

在此测试中,最佳数量等于机器中的核心数。

答案 2 :(得分:46)

我知道这个问题相当陈旧,但自2009年以来情况有所发展。

现在需要考虑两件事:核心数量,以及每个核心内可以运行的线程数。

使用Intel处理器,线程数由超线程定义,仅为2(如果可用)。但即使不使用2个线程,超线程也会将执行时间缩短两倍! (即在两个进程之间共享一条管道 - 当你有更多进程时这很好,否则就不那么好了。更多内核肯定会更好!)

在其他处理器上,您可能有2个,4个甚至8个线程。因此,如果您有8个内核,每个内核支持8个线程,则可以并行运行64个进程而无需上下文切换。

如果您使用标准操作系统运行,“无上下文切换”显然不正确,该操作系统将针对您无法控制的各种其他事情进行上下文切换。但那是主要的想法。某些操作系统允许您分配处理器,因此只有您的应用程序才能访问/使用所述处理器!

根据我自己的经验,如果你有很多I / O,多线程是好的。如果你有非常繁重的内存密集型工作(读取源1,读取源2,快速计算,写入),那么拥有更多线程无济于事。同样,这取决于您同时读取/写入多少数据(即,如果您使用SSE 4.2并读取256位值,则会停止其步骤中的所有线程...换句话说,1个线程可能更容易实现,并且可能几乎同样快速,如果实际上不快。这将取决于您的过程和内存架构,一些高级服务器管理单独内核的单独内存范围,因此假设您的数据正确归档,单独的线程将更快...这就是为什么,在一些架构,4个进程的运行速度比4个进程的进程快。)

答案 3 :(得分:22)

实际表现取决于每个线程自愿产生的收益。例如,如果线程根本不进行I / O并且不使用系统服务(即它们是100%cpu绑定的),那么每个核心1个线程是最佳的。如果线程执行任何需要等待的操作,那么您将不得不尝试确定最佳线程数。 4000个线程会产生大量的调度开销,因此这可能也不是最优的。

答案 4 :(得分:18)

答案取决于程序中使用的算法的复杂程度。我想出了一种方法,通过对两个任意数量的线程'n'和'm'进行两次处理时间Tn和Tm来计算最佳线程数。对于线性算法,最佳线程数将为N = sqrt((m n (Tm *(n-1) - Tn *(m-1)))/(n Tn -m Tm))。

请阅读我关于各种算法最佳数量计算的文章:pavelkazenin.wordpress.com

答案 5 :(得分:7)

一次4000个线程非常高。

答案是肯定的,不是。如果你在每个线程中做了很多阻塞I / O,那么是的,你可以显示出显着的加速,每个逻辑核心可能有3或4个线程。

如果你没有做很多阻塞事情,那么线程的额外开销会让它变慢。因此,请使用分析器,查看每个可能平行的部件中瓶颈的位置。如果您正在进行繁重的计算,那么每个CPU超过1个线程将无济于事。如果你正在进行大量的内存传输,它也无济于事。如果您正在进行大量I / O,例如磁盘访问或Internet访问,那么多个线程将在一定程度上提供帮助,或者至少使应用程序更具响应性。

答案 6 :(得分:7)

我以为我会在这里添加另一个视角。答案取决于问题是假设弱缩放还是强缩放。

来自Wikipedia

弱缩放:解决方案时间如何随每个处理器的固定问题大小的处理器数量而变化。

强缩放:解决方案时间如何随固定总问题规模的处理器数量而变化。

如果问题是假设缩小,那么@ Gonzalo的答案就足够了。但是,如果问题是假设强大的扩展,那么还需要添加更多内容。在强大的扩展中,您假设工作负载大小固定,因此如果增加线程数,则每个线程需要处理的数据大小会减小。在现代CPU上,内存访问非常昂贵,并且通过将数据保存在缓存中来维护本地性更为可取。因此,当每个线程的数据集适合每个核心的缓存 时,可以找到可能的最佳线程数 (我不会进入讨论它是否是系统的L1 / L2 / L3缓存的细节。

即使线程数超过核心数,也是如此。例如,假设程序中有8个任意单位(或AU)工作,将在4核机器上执行。

案例1:以四个线程运行,每个线程需要完成2AU。每个线程需要10秒才能完成( 有很多缓存未命中 )。使用四个内核时,总时间将为10秒(10秒* 4线程/ 4个内核)。

案例2:以八个线程运行,每个线程需要完成1AU。每个线程只需2秒(而不是5秒,因为 减少了缓存未命中量 )。使用8个内核时,总时间将为4秒(2s * 8个线程/ 4个内核)。

我已经简化了问题并忽略了其他答案中提到的开销(例如,上下文切换),但希望您明白拥有比可用核心数更多的线程可能是有益的,具体取决于您正在处理的数据大小。

答案 7 :(得分:6)

基准。

我开始增加应用程序的线程数,从1开始,然后转到100,为每个线程数运行三到五次试验,并自己构建一个运行速度与线程数。

你应该认为四线程案例是最优的,之后运行时略有上升,但也许不是。可能是您的应用程序带宽有限,即您加载到内存中的数据集很大,您获得了大量缓存未命中等,因此2个线程是最佳的。

在测试之前你无法知道。

答案 8 :(得分:3)

您可以通过运行htop或ps命令来查找机器上可以运行多少个线程,这些命令可以返回机器上的进程数。

您可以使用有关'ps'命令的手册页。

man ps

如果要计算所有用户进程的数量,可以使用以下命令之一:

  1. ps -aux| wc -l
  2. ps -eLf | wc -l
  3. 计算用户进程的编号:

    1. ps --User root | wc -l
    2. 另外,您可以使用“htop” [Reference]

      在Ubuntu或Debian上安装:

      sudo apt-get install htop
      

      在Redhat或CentOS上安装:

      yum install htop
      dnf install htop      [On Fedora 22+ releases]
      

      如果你想从源代码编译htop,你会发现它here

答案 9 :(得分:2)

理想情况是每个核心有1个线程,只要没有线程阻塞。

可能不是这样的一种情况:在核心上运行其他线程,在这种情况下,更多线程可能会给程序更大的执行时间。

答案 10 :(得分:2)

许多线程(“线程池”)与每个核心一个的一个例子是在Linux或Windows中实现Web服务器。

由于在Linux中轮询套接字,很多线程可能会增加其中一个线程在正确的时间轮询正确套接字的可能性 - 但整体处理成本会非常高。

在Windows中,服务器将使用I / O完成端口 - IOCP实现 - 这将使应用程序事件驱动:如果I / O完成操作系统,则启动备用线程来处理它。当处理完成时(通常使用请求 - 响应对中的另一个I / O操作),线程返回到IOCP端口(队列)以等待下一次完成。

如果没有完成I / O,则无法完成任何处理,也没有启动任何线程。

实际上,Microsoft建议在IOCP实现中每个核心不超过一个线程。任何I / O都可以附加到IOCP机制。如有必要,申请也可以发布IOC。

答案 11 :(得分:0)

从计算和内存绑定的角度来讲(科学计算)4000线程将使应用程序运行速度非常慢。问题的一部分是上下文切换的开销非常高,很可能是非常差的内存局部性。

但这也取决于你的架构。从我听说Niagara处理器假设能够使用某种先进的流水线技术处理单个核心上的多个线程。但是我对这些处理器没有经验。

答案 12 :(得分:0)

希望这是有道理的,检查CPU和内存利用率并设置一些阈值。如果超过阈值,则不允许创建新线程,否则允许...