Python:多处理,加载8/24核心

oop*_*ode 9 python multiprocessing

我有一台机器有24个物理核心(至少我被告知)运行Debian : Linux 3.2.0-4-amd64 #1 SMP Debian 3.2.68-1+deb7u1 x86_64 GNU/Linux. 这似乎是正确的:

usr@machine:~/$ cat /proc/cpuinfo  | grep processor
processor   : 0
processor   : 1
<...>
processor   : 22
processor   : 23
Run Code Online (Sandbox Code Playgroud)

我试图用Python加载所有内核时遇到了一些问题multiprocessing.pool.Pool.我用过Pool(processes=None); 文档说Python使用cpu_count()if None提供.

唉,只有8个核心100%加载,其他核心闲置(我用来htop监控CPU负载).我以为我无法正常烹饪Pools并尝试"手动"调用24个进程:

print 'Starting processes...'
procs = list()
for param_set in all_params:  # 24 items
    p = Process(target=_wrap_test, args=[param_set])
    p.start()
    procs.append(p)

print 'Now waiting for them.'
for p in procs:
    p.join()
Run Code Online (Sandbox Code Playgroud)

我从我开始的流程中收到了24条"问候"消息:

Starting processes...
Executing combination: Session len: 15, delta: 10, ratio: 0.1, eps_relabel: 0.5, min_pts_lof: 5, alpha: 0.01, reduce: 500
< ... 22 more messages ... >
Executing combination: Session len: 15, delta: 10, ratio: 0.1, eps_relabel: 0.5, min_pts_lof: 7, alpha: 0.01, reduce: 2000
Now waiting for them.
Run Code Online (Sandbox Code Playgroud)

仍然只加载了8个核心:

在此输入图像描述

我在这里读到可能存在numpyOpenBLAS和多核执行问题.这就是我启动代码的方式:

OPENBLAS_MAIN_FREE=1 python -m tests.my_module
Run Code Online (Sandbox Code Playgroud)

在完成所有进口之后我做了:

os.system("taskset -p 0xff %d" % os.getpid())
Run Code Online (Sandbox Code Playgroud)

所以,问题是:我应该怎样做才能在所有内核上实现100%的负载?这只是我糟糕的Python使用情况还是与多核计算机上的操作系统限制有关?

更新:另一个有趣的事情是htop输出中的一些不一致.如果你看一下上面的图像,你会发现CPU负载条下面的表显示了超过8个内核的30-50%负载,这与负载条所说的完全不同.然后,top似乎同意那些条:8个核心100%负载,其他闲置.

再次更新:

当我在所有导入后添加行时,我在SO上使用了这个相当受欢迎的帖子os.system("taskset -p 0xff %d" % os.getpid()).我必须承认,当我这样做时,我并没有想太多,特别是在阅读之后:

在模块导入后粘贴此行,我的示例现在在所有核心上运行

我是一个单纯的男人.我看到"像魅力一样",我复制并粘贴.无论如何,在玩我的代码时,我最终删除了这一行.之后,我的代码开始在所有24个内核上执行"手动" Process启动方案.对于该Pool场景,无论是否使用亲和力技巧,仍然存在相同的问题.

我不认为这是一个真正的答案'因为我不知道问题是什么Pool,但至少我设法让所有核心满载.谢谢!

nox*_*fox 4

即使您解决了问题,我也会尝试解释它以澄清想法。

据我了解,numpy 做了很多“魔法”来提高性能。技巧之一是设置进程的 CPU 亲和性。

CPU亲和性是操作系统调度程序的优化。它基本上强制给定进程始终在同一 CPU 核心上运行。

这提高了性能,减少了 CPU 缓存失效的次数,并增加了引用局部性的好处。在高计算任务中,这些因素确实很重要。

我不喜欢 numpy 的地方是它隐式地完成了这一切。常常让开发人员感到困惑。

您的进程未在所有核心上运行的事实是由于 numpy 在导入模块时设置了与父进程的亲和力。然后,当您生成新进程时,亲和力会被继承,导致所有进程争夺少数核心,而不是有效地使用所有可用的核心。

os.system("taskset -p 0xff %d" % os.getpid())命令指示操作系统重新设置所有核心上的关联性以解决您的问题。

如果您想看到它在池中运行,您可以执行以下技巧。

import os
from multiprocessing import Pool


def set_affinity_on_worker():
    """When a new worker process is created, the affinity is set to all CPUs"""
    print("I'm the process %d, setting affinity to all CPUs." % os.getpid())
    os.system("taskset -p 0xff %d" % os.getpid())


if __name__ == '__main__':
    p = Pool(initializer=set_affinity_on_worker)
    ...
Run Code Online (Sandbox Code Playgroud)