多处理池大小 - cpu_count 或 cpu_count/2?

Multiprocessing pool size - cpu_count or cpu_count/2?

我是 运行 python 在相当大的 aws 实例(48 或 96 vCPU)上进行批量数据处理的脚本。 multiprocessing.Pool() 工作得很好:工作人员与主进程的通信最少(采用文件路径,return True/False)。 I/O 内存似乎没有限制。

我的性能参差不齐,其中有时最佳速度来自池大小 = vCPU 的数量,有时来自 vCPU/2 的数量,有时 vCPU * 一些大约 2-4 的倍数。这些适用于不同类型的工作,在不同的情况下,因此很难对所有这些进行基准测试。

对于使用多大的池有经验法则吗?

P.S。 multiprocessing.cpu_count() returns 一个数字,好像等于vCPU的数量。如果这是一致的,我想选择一些合理的 cpu_count 倍数,然后就这样。

您可以遵循许多经验法则,具体取决于您已经了解的任务

  • 物理 核心数
  • 逻辑核心数
  • 物理或逻辑核心数减去一个(假设为逻辑和控制保留一个核心)

为了避免计算逻辑内核而不是物理内核,我建议使用 psutil 库:

import psutil
psutil.cpu_count(logical=False)

至于到底用什么,对于数值密集型的应用,我倾向于选择物理内核的数量。请记住,某些 BLAS 实现默认使用多线程,这可能会严重损害数据并行管道的可扩展性。每当进行批处理时,使用 MKL_NUM_THREADS=1OPENBLAS_NUM_THREADS=1(取决于您的 BLAS 后端)作为环境变量,您应该具有准线性加速 w.r.t。物理核心数。

这些数字的原因:

  1. vCPU数量:合理,我们使用所有核心。
  2. number of vCPU/2:这也是合理的,因为与物理内核相比,有时我们有双倍的逻辑内核。但是逻辑核心实际上不会加速你的程序,所以我们只使用 vCPU/2.
  3. vCPU*some multiple around 2-4: 对于一些IO密集型的任务是合理的。对于这类任务,进程并不是一直在占用核心,所以我们可以在IO操作的时候调度一些其他的任务。

那么现在让我们分析一下情况,我猜你是 运行 在一个可能是 VPS 的服务器上。在这种情况下,逻辑核心和物理核心之间没有区别,因为 vCPU 只是 VPS 提供者提供的抽象计算资源。你无法真正触及底层的物理内核。

如果你的主进程不是计算密集型的,或者说它只是一个简单的控制器,那么你不需要为它分配一个完整的核心,这意味着你不需要减去一个。

根据你的情况,我想建议一下vCPU的数量。但是还是需要根据自己遇到的真实情况来决定。关键规则是:

最大限度地利用资源(尽可能多地使用内核),最大限度地减少资源竞争(过多的进程会争夺资源,这会拖慢整个程序)。