为什么多处理在导入 numpy 之后只使用一个内核?

我不确定这是否更像是一个操作系统问题,但是我认为我应该在这里问一下,以防有人对 Python 有什么见解。

我一直在尝试使用 joblib并行处理一个 CPU 占用较多的 for循环,但是我发现不是每个工作进程被分配到一个不同的内核,而是所有工作进程都被分配到同一个内核,没有性能提高。

这里有一个非常微不足道的例子..。

from joblib import Parallel,delayed
import numpy as np


def testfunc(data):
# some very boneheaded CPU work
for nn in xrange(1000):
for ii in data[0,:]:
for jj in data[1,:]:
ii*jj


def run(niter=10):
data = (np.random.randn(2,100) for ii in xrange(niter))
pool = Parallel(n_jobs=-1,verbose=1,pre_dispatch='all')
results = pool(delayed(testfunc)(dd) for dd in data)


if __name__ == '__main__':
run()

... 这是我在 htop中看到的,当这个脚本运行的时候:

htop

我在一台4核的笔记本电脑上运行 Ubuntu 12.10(3.5.0-26)。显然,joblib.Parallel正在为不同的工作者产生不同的进程,但是有没有办法让这些进程在不同的核上执行呢?

45455 次浏览

这似乎是 Python 在 Ubuntu 上的一个常见问题,而且不是特定于 joblib的:

我建议尝试 CPU 亲和力(taskset)。

在更多的谷歌搜索后,我找到了答案 给你

事实证明,某些 Python 模块(numpyscipytablespandasskimage...)在导入时与核心关联相混乱。据我所知,这个问题似乎是由它们链接到多线程 OpenBLAS 库而引起的。

解决方案是使用

os.system("taskset -p 0xff %d" % os.getpid())

在模块导入之后粘贴了这一行,我的示例现在可以在所有核上运行:

htop_workaround

到目前为止,我的经验是,这似乎对 numpy的性能没有任何负面影响,尽管这可能是机器和任务特定的。

更新:

还有两种方法可以禁用 OpenBLAS 本身的 CPU 关联重置行为。例如,在运行时可以使用环境变量 OPENBLAS_MAIN_FREE(或 GOTOBLAS_MAIN_FREE)

OPENBLAS_MAIN_FREE=1 python myscript.py

或者,如果您从源代码编译 OpenBLAS,您可以在构建时通过编辑 Makefile.rule以包含该行来永久禁用它

NO_AFFINITY=1

Python3现在公开 方法以直接设置关联

>>> import os
>>> os.sched_getaffinity(0)
{0, 1, 2, 3}
>>> os.sched_setaffinity(0, {1, 3})
>>> os.sched_getaffinity(0)
{1, 3}
>>> x = {i for i in range(10)}
>>> x
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> os.sched_setaffinity(0, x)
>>> os.sched_getaffinity(0)
{0, 1, 2, 3}