Answers:
如果您的线程不执行I / O,同步等操作,并且没有其他任何运行,则每个内核1个线程将为您带来最佳性能。但是,事实并非如此。添加更多的线程通常会有所帮助,但是在某些时候,它们会导致性能下降。
不久前,我在负载相当不错的Mono上运行ASP.NET应用程序的2四核计算机上进行了性能测试。我们使用了最小和最大线程数,最后发现,对于在特定配置中的特定应用程序,最佳吞吐量在36至40个线程之间。在这些界限之外的任何事情都表现得更糟。学过的知识?如果我是你,我将使用不同数量的线程进行测试,直到找到适合您的应用程序的正确数量。
可以肯定的一件事:4k线程将花费更长的时间。那是很多上下文切换。
我同意@Gonzalo的回答。我有一个不执行I / O的过程,这是我发现的结果:
请注意,所有线程都在一个数组上工作,但范围不同(两个线程不能访问相同的索引),因此,如果它们在不同的数组上工作,结果可能会有所不同。
1.86机器是带有SSD的macbook air。另一台Mac是具有普通HDD(我认为是7200 rpm)的iMac。Windows机器还具有7200 rpm的硬盘。
在此测试中,最佳数量等于机器中的核心数量。
我知道这个问题比较老,但是自2009年以来情况已经发生了变化。
现在要考虑两件事:内核数,以及每个内核中可以运行的线程数。
对于Intel处理器,线程数由超线程定义,该线程只有2个(如果可用)。但是,即使不使用2个线程,超线程也可以将执行时间减少两倍!(即,两个进程之间共享1条管道-当您拥有更多进程时,这很好,否则就不好了。更多的内核肯定会更好!)
在其他处理器上,您可能具有2、4甚至8个线程。因此,如果您有8个内核,每个内核都支持8个线程,则可以有64个并行运行的进程而无需上下文切换。
如果您在标准操作系统上运行,则“无上下文切换”显然是不正确的,该操作系统将对您无法控制的所有其他事情进行上下文切换。但这是主要思想。一些操作系统允许您分配处理器,因此只有您的应用程序可以访问/使用该处理器!
根据我自己的经验,如果您有很多I / O,那么多线程比较好。如果您有大量的内存密集型工作(读取源1,读取源2,快速计算,写入),那么拥有更多线程将无济于事。同样,这取决于同时读取/写入多少数据(即,如果您使用SSE 4.2并读取256位值,则这将停止所有线程的步...换句话说,一个线程可能更容易实现,并且如果不是真的更快的话,速度可能差不多快。这取决于您的进程和内存架构,一些高级服务器为单独的内核管理单独的内存范围,因此假设您的数据已正确归档,单独的线程会更快...这就是为什么在某些情况下架构,则4个进程的运行速度将比具有4个线程的1个进程快。)
答案取决于程序中使用的算法的复杂性。我想出了一种方法,通过对两个任意数量的线程“ n”和“ m”进行两次处理时间Tn和Tm的测量来计算最佳线程数。对于线性算法,最佳线程数为N = sqrt((m n(Tm *(n-1)– Tn *(m-1)))/(n Tn-m Tm))。
请阅读我的文章,了解有关各种算法的最佳数的计算:pavelkazenin.wordpress.com
我以为我会在这里添加另一个观点。答案取决于问题是假设是弱缩放还是强缩放。
从维基百科:
扩展能力弱:对于每个处理器固定的问题大小,解决时间如何随处理器数量的变化而变化。
强大的扩展能力:对于固定的总问题大小,解决时间如何随处理器数量的变化而变化。
如果问题是假设缩放较弱,则@Gonzalo的答案就足够了。但是,如果问题是要进行强扩展,则还有更多需要添加的内容。在强扩展中,您假设工作负载大小固定,因此,如果增加线程数,则每个线程需要处理的数据大小会减少。在现代CPU上,内存访问非常昂贵,因此最好通过将数据保存在缓存中来保持局部性。因此,当每个线程的数据集适合每个内核的缓存时,可以找到可能的最佳线程数(我不讨论讨论它是否是系统的L1 / L2 / L3缓存的细节)。
即使线程数超过内核数,也是如此。例如,假设程序中有8个任意工作单元(或AU),这些工作将在4核计算机上执行。
情况1:使用四个线程运行,其中每个线程需要完成2AU。每个线程需要10秒钟才能完成(有很多高速缓存未命中)。如果使用四个内核,则总时间将为10s(10s * 4个线程/ 4个内核)。
情况2:以八个线程运行,每个线程需要完成1AU。每个线程仅花费2s(而不是5s,因为减少了高速缓存未命中次数)。如果使用四个内核,则总时间将为4s(2s * 8个线程/ 4个内核)。
我已经简化了问题,并忽略了其他答案(例如,上下文切换)中提到的开销,但是希望您明白,根据您的数据大小,拥有更多数量的线程可能比可用的核心数量更有益。重新处理。
您可以通过运行htop或ps命令找到可以在计算机上运行的线程数,这些命令返回计算机上的进程数。
您可以使用有关“ ps”命令的手册页。
man ps
如果要计算所有用户进程的数目,可以使用以下命令之一:
ps -aux| wc -l
ps -eLf | wc -l
计算用户进程数:
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,请在此处找到它。
多线程(“线程池”)与每个内核一个线程的一个例子是在Linux或Windows中实现Web服务器的例子。
由于套接字是在Linux中轮询的,因此许多线程可能会增加其中一个线程在正确的时间轮询正确的套接字的可能性-但总体处理成本将非常高。
在Windows中,将使用I / O完成端口(IOCP)来实现服务器,这将驱动应用程序事件驱动:如果I / O完成,则操作系统将启动一个备用线程来处理它。处理完成后(通常使用另一个I / O操作(如请求-响应对)),线程返回IOCP端口(队列)以等待下一个完成。
如果没有I / O完成,则不执行任何处理,也不启动线程。
确实,Microsoft建议在IOCP实现中每个核心不超过一个线程。可以将任何I / O附加到IOCP机制。如果需要,IOC也可以由应用程序发布。
timeout is an upper bound on the amount of time elapsed before select() returns. If both fields of the timeval structure are zero, then select() returns immediately. (This is useful for polling.) If timeout is NULL (no timeout), select() can block indefinitely.