运行 比 CPU 多得多的作业的效率

Efficiency of running many more jobs than CPUs

我有一大堆作业 运行(数千),每个 CPU 需要 30 分钟到几个小时。内存要求很小(每个几 KB)。我正在处理一个有几十个 CPU 的小型 linux 集群。到目前为止,我一直在启动它们 运行 一次启动几个,试图手动让集群保持忙碌。

我的问题是:如果我一次提交数百或数千个 - 远远超过 CPU 的数量会怎样?很明显,每个作业单独 运行 会花费更长的时间,但我想知道这种方法的整体效率与每个 CPU 一次只有一个作业的效率相比。我还可以编写一个更复杂的方法来监视进度并让每个 CPU 只占用一个工作(例如,在 Python 中使用多处理),但这会占用昂贵的程序员时间,而且我想知道最终结果是否真的会更快。

像很多事情一样,这取决于。

如果您有 I/O 或远程处理,例如文件工作、数据库访问、Web 服务或其他远程调用,那么通常有大量空闲 CPU 时间等待这些完成。在这些情况下,拥有比 CPU 多的工作通常是有益的。这显然有一些限制,但计算和解决确切的阈值将在您的 "costly programmer time".

范围内

CPU-绑定进程很可能会在您添加进程时阻塞。

再次针对 CPU 绑定,而不是您描述的 "push" 方法是将其翻转过来。有一个排队机制,工作人员 threads/processes(每个 CPU 1 个)从主队列中提取工作。 master queue 是轻量级的,当它没有被要求做任何事情时就会进入睡眠状态,而 worker 只会咀嚼工作。

虽然在不了解问题的更多细节的情况下很难给你一个明确的答案,但总而言之。

祝你好运!

在速度方面,您不太可能通过产生比可用物理线程更多的线程来提高性能除非您的线程花费大量时间休眠(其中如果它给你的其他线程一个执行的机会)。请注意,线程休眠可以隐式隐藏在 I/O 绑定进程中以及竞争锁时。

这实际上取决于您的线程是否花费大部分时间等待某些事情(例如:来自服务器的更多数据、让用户做某事、更新文件、访问锁定的资源)或尽可能快地并行进行。如果是后一种情况,使用比实际可用的线程更多的线程往往会减慢您的速度。拥有比任务多的线程可以提高吞吐量的唯一方法是当这些线程浪费时间休眠时,为其他线程在休眠时做更多事情提供机会。

但是,生成所有这些任务并让操作系统处理调度可能会让事情变得更容易。

有了更多的线程,您可能会减慢速度(即使在吞吐量方面)。这在某种程度上取决于您的调度和线程池的工作方式以及这些线程是否花时间休眠,但是构建线程不一定是一件便宜的事情,并且具有那么多线程的上下文切换可能比您自己的调度过程更昂贵比只看到大量需要执行的线程的操作系统有更多关于你想做什么以及什么时候合适的信息。

像 Intel 的 Thread Building Blocks 这样的高效库将池中的线程数与物理硬件相匹配(不多也不少)是有原因的。它往往是最有效的路线,但考虑到需要手动调度、工作窃取等,它是最难实现的。所以有时一次产生大量线程可能很方便,但你通常不会这样做这样做是一种优化,除非您 I/O 像其他答案中指出的那样受到约束,并且您的线程只是将大部分时间花在睡眠和等待输入上。

如果您有这样的需求,充分利用它的最简单方法是找到一个好的并行处理库(例如:PPL、TBB、OMP 等)。然后你只需编写一个并行循环,让库专注于如何最有效地处理线程并平衡它们之间的负载。对于这些情况,您关注的是任务应该做什么,但不一定关注它们何时执行。

如果您使用线程,通常最好使用线程池。如果不这样做,您的 CPU 将被上下文切换阻塞。也就是说,内核显然使用技巧来确保这在所有情况下都不是真正的问题。

我对结合使用大量 CPU 能力的(小)进程的经验是,最好将线程数限制为 -say- 4 * 处理器数量。通常会有一些启动期等。这就是 4* 在那里的原因。

如果你使用 async-stuff,它可能会自动使用轮询和线程池等技巧,这意味着它会工作得很好。我在这里的经验是异步的东西通常比 IO 的线程更好。