每个核心的最佳线程数

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

因为我有4个内核,所以我不期望通过运行比内核更多的线程来提高速度,因为单个内核在给定时刻只能运行单个线程。我对硬件了解不多,所以这只是一个猜测。

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

242714 次浏览

理想的情况是每个内核有一个线程,只要没有线程会阻塞。

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

实际性能取决于每个线程的自愿屈服程度。例如,如果线程根本不做I/O,也不使用任何系统服务(即它们100%受cpu限制),那么每个核1个线程是最优的。如果线程执行任何需要等待的操作,那么您必须试验以确定最佳线程数。4000个线程会导致大量的调度开销,所以这可能也不是最优的。

如果你的线程不做I/O,同步等,没有其他的运行,1个线程一个核可以让你获得最好的性能。然而,情况很可能并非如此。添加更多的线程通常会有所帮助,但在某种程度上,它们会导致性能下降。

不久前,我在一台运行ASP的2核四核机器上做性能测试。NET应用程序在Mono上的一个相当不错的负载。我们尝试了最小和最大线程数,最后我们发现,对于特定配置下的特定应用程序,最佳吞吐量在36到40个线程之间。任何超出这些界限的东西表现得更差。课学到了什么?如果我是您,我会使用不同数量的线程进行测试,直到为您的应用程序找到合适的线程数量。

有一件事是肯定的:4k线程将花费更长的时间。这有很多上下文转换。

一次4000个线程是相当高的。

答案是肯定的,也不是。如果您在每个线程中执行大量阻塞I/O,那么是的,您可以在每个逻辑核心中执行3或4个线程时显示显著的加速。

然而,如果你没有做很多阻塞的事情,那么线程的额外开销只会使它变慢。因此,使用分析器查看每个可能并行的部分的瓶颈在哪里。如果您正在进行繁重的计算,那么每个CPU超过1个线程是没有帮助的。如果你正在做大量的内存传输,它也不会有帮助。如果你正在做大量的I/O,比如磁盘访问或互联网访问,那么多线程在一定程度上是有帮助的,或者至少让应用程序反应更快。

基准。

我会开始增加应用程序的线程数,从1开始,然后增加到100,对每个线程数运行3 - 5次试验,并建立一个操作速度与线程数的关系图。

您应该认为四个线程的情况是最优的,在此之后运行时略有增加,但也可能不是。这可能是你的应用程序带宽有限,也就是说,你加载到内存中的数据集是巨大的,你得到了很多缓存失误,等等,这样2个线程是最佳的。

你不测试就不知道。

从计算和内存限制的角度(科学计算)来说,4000个线程会让应用程序运行得非常慢。部分问题是上下文切换的开销非常高,而且很可能是内存位置非常差。

但这也取决于您的体系结构。我听说Niagara处理器应该能够使用某种先进的流水线技术在单核上处理多个线程。但是我没有使用这些处理器的经验。

大量线程(“线程池”)vs每个核心一个线程的一个例子是在Linux或Windows中实现web服务器。

由于在Linux中套接字是轮询的,因此许多线程可能会增加其中一个线程在正确的时间轮询正确的套接字的可能性——但总体处理成本将非常高。

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

如果没有I/O完成,就没有要做的处理,也没有启动线程。

事实上,微软建议在IOCP实现中每个核不超过一个线程。任何I/O都可以附加到IOCP机制。如果需要,应用程序也可以发布IOCs。

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

enter image description here

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

这台1.86版本的机器是一台带有SSD的macbook air。另一台mac是一台iMac,硬盘正常(我想转速是7200转)。这台装有windows操作系统的机器还有一个7200转的硬盘。

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

我知道这个问题很老了,但事情从2009年开始就有了变化。

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

对于Intel处理器,线程的数量是由Hyperthreading定义的,只有2个(如果可用)。但是超线程将您的执行时间缩短了两个,即使不使用两个线程!(例如,两个进程共享一个管道——当你有更多的进程时,这很好,否则就不太好了。更多的核心肯定更好!)注意,现代cpu通常有更多的管道来划分工作负载,所以它不再被一分为二了。但是超线程仍然在两个线程之间共享大量的CPU单元(有些人称之为逻辑cpu)。

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

“没有上下文切换”;如果你使用的是一个标准的操作系统,它会对各种你无法控制的事情进行上下文切换,这显然是不正确的。但这是主要的思想。一些操作系统允许你分配处理器,这样只有你的应用程序可以访问/使用处理器!

根据我自己的经验,如果你有很多I/O,多线程是很好的。如果你有非常重的内存密集型工作(读取源1,读取源2,快速计算,写入),那么更多的线程是没有帮助的。同样,这取决于你同时读/写多少数据(例如,如果你使用SSE 4.2并读取256位的值,这将停止所有线程在他们的步骤…换句话说,1线程可能更容易实现,而且速度可能和线程一样快(如果不是更快的话)。这将取决于你的过程&内存架构,一些高级服务器为不同的核心管理不同的内存范围,所以如果你的数据被正确归档,分开的线程会更快……这就是为什么在某些架构上,4个进程比一个4个线程的进程运行得更快。)

答案取决于程序中使用的算法的复杂性。我提出了一个计算最佳线程数的方法,即对任意数量的线程“n”和“m”进行两次处理时间Tn和Tm的测量。对于线性算法,最佳线程数为N =√(mn(Tm*(N -1) - Tn*(m-1)) /(nTn-mTm))。

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

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

我想在这里补充另一个观点。答案取决于这个问题是假设弱缩放还是强缩放。

维基百科:

弱比例:对于每个处理器的固定问题大小,解决时间如何随处理器数量而变化。

强大的扩展:对于一个固定的总问题大小,解决时间如何随处理器数量而变化。

如果这个问题是假设弱缩放,那么@Gonzalo的答案就足够了。然而,如果问题是假设强伸缩性,那么还需要添加更多的东西。在强伸缩性中,您假设固定的工作负载大小,因此如果您增加线程数量,每个线程需要处理的数据大小就会减少。在现代cpu上,内存访问是昂贵的,最好通过将数据保存在缓存中来保持局部性。因此,可能的最佳线程数可以找到当每个线程的数据集适合每个核心的缓存时,(我不打算详细讨论它是否是系统的L1/L2/L3缓存)。

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

案例1:运行与四个线程,其中每个线程需要完成2AU。每个线程需要10秒来完成(with a lot cache misses)。对于四个内核,总时间为10s (10s * 4个线程/ 4个内核)。

案例2:运行八个线程,其中每个线程需要完成1AU。每个线程只需要2s(而不是5s,因为减少缓存丢失的数量)。如果是四核,总时间为4s (2s * 8线程/ 4核)。

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

通过运行htop或ps命令(返回机器上的进程数),您将发现可以在机器上运行多少个线程。

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

man ps

如果你想计算所有用户进程的数量,你可以使用这些命令之一:

  1. ps -aux| wc -l
  2. ps -eLf | wc -l

计算用户进程数:

  1. ps --User root | wc -l

另外,你可以使用"htop"(参考):

在Ubuntu或Debian上安装:

sudo apt-get install htop

在Redhat或CentOS上安装:

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

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