多任务处理时的最佳线程数

多任务处理时的最佳线程数

我知道有人问过类似的问题,但我认为我的情况有点不同。

假设我有一台具有 8 个内核和无限内存并搭载 Linux 操作系统的计算机。

我有一款名为 Gaussian 的计算软件,它可以利用多线程。因此,我将单次计算的线程数设置为 8,以获得最大速度。但是,当我需要同时运行 8 次计算时,我真的无法决定该怎么做。在这种情况下,我应该将线程数设置为 1(8 个进程中总共生成 8 个线程)还是将其保留为 8(8 个进程中总共生成 64 个线程)?这真的很重要吗?一个相关的问题是,操作系统是否会自动将每个线程的核心停放在不同的核心上?

编辑:我知道基准测试是最好的了解方法。问题是,这些计算机属于我的大学,所以它们一直很忙。换句话说,它的工作量变化对我来说是无法控制的,因为其他人也在使用这些计算机进行计算,这使得实验变得不可能。此外,该软件非常昂贵(1500 美元左右),并且每台计算机都需要许可,因此我不能简单地在我的个人计算机上运行基准测试......

答案1

正确的数字取决于进程在 IO 上阻塞的时间。

《JVM 上的并发编程》这本书对此有一些很好的信息:

“确定线程数”。对于大问题,我们希望线程数至少与可用核心数相同。这将确保尽可能多的核心可用于解决我们的问题...

因此,最小线程数等于可用内核数。如果所有任务都是计算密集型的,那么这就是我们所需要的。在这种情况下,拥有更多线程实际上会造成不利影响,因为当仍有工作要做时,内核会在线程之间进行上下文切换。如果任务是 IO 密集型的,那么我们应该拥有更多线程。

当任务执行 IO 操作时,其线程会被阻塞。处理器会立即切换上下文以运行其他符合条件的线程。如果我们的线程数与可用内核数一样多,即使我们有任务要执行,它们也无法运行,因为我们没有将它们安排在线程上以供处理器接手。

如果任务被阻塞的时间占 50%,那么线程数应该是可用核心数的两倍。如果任务被阻塞的时间较少(即计算密集型),那么线程数应该较少,但不应少于核心数。如果任务被阻塞的时间较长(即 IO 密集型),那么线程数应该较多,具体而言是核心数的几倍。

因此我们可以按如下方式计算所需的线程总数:

线程数 = 可用核心数 / (1 - 阻塞系数)

如果您需要同时运行多个计算,也许可以看看是否可以使用大小适当的线程池在一个进程内运行它们。

否则,如果您具有用于一次计算的最佳线程数,但每次运行 8 个线程,则线程数可能太多了。

最好的解决方案是通过实验进行基准测试。

我不太清楚你说的核心停顿是什么意思,但出于缓存原因,CPU 倾向于在给定核心上继续运行相同的线程,尽管有时也会出于不同的热量/功率原因而移动它。你可以使用 htop 之类的工具来调查这一点。

答案2

理想情况下,所有作业的总线程数应为系统的核心数,但支持超线程的系统除外,在这些系统中,线程数应为核心数的两倍。因此,如果系统没有超线程,则有 8 个计算正在运行,每个计算都应在一个线程中运行。

许多英特尔处理器都具有超线程功能,因此每个核心可以支持两个线程。例如,支持超线程的 8 核系统应该有 16 个线程才能充分利用系统。

答案3

答案取决于进程的作用以及其多线程编程方式,这意味着您需要进行实验。

如果进程使用信号量和其他排除机制来解决线程之间对公共资源(例如内存)的争用,那么进程中的线程数越少,引起等待的冲突次数就越少。

在等待期间,线程不执行任何操作,因此等待会对吞吐量产生负面影响。在这种情况下,更多的进程和每个进程更少的线程将提高吞吐量,因此 8x8 的性能将优于 1x64。

另一方面,如果每个线程都是完全独立的,并且没有共享的公共资源,那么操作系统将对线程进行调度,而不会区分 8x8 或 1x64 两种情况。在这种情况下,只有线程总数对总吞吐量很重要,因此两种情况的性能相同。

答案4

你们自己已经回答了这个问题。“这些计算机属于我的大学,所以它们一直很忙”

实际上你只使用了一部分处理器。为了以最高效的方式完成工作,任务切换和多路复用以及资源等待的开销应该最小化,因此你应该始终考虑使用单线程来执行。

由于上下文切换的开销,基于“处理能力”计算时,多线程总是效率较低。它只会利用所有“空闲”的未占用资源来加快问题的速度。想法:使用 8 台计算机来运行问题,速度可能提高 7.9 倍,但永远不会超过 8。

如果所有这些都是专门为您而设的,那么只需并行执行即可加快速度,如果不是,请保持单线程并让其他人使用剩余的核心进行其他工作。

顺便说一句,出于自私的考虑,有一个叫 grid 的红帽工具可以将您的工作分派到校园内的所有 Linux 上。(>200)。它运行得非常快,只要不被抓住,因为它会拖慢所有人的速度。或者使用旧工具 mathlab parallel。

相关内容