[英]Importing scipy breaks multiprocessing support in Python
我遇到了一个我无法解释的奇怪问题。 我希望那里有人可以帮忙!
我正在运行Python 2.7.3和Scipy v0.14.0,我正在尝试实现一些非常简单的多处理器算法,以使用模块multiprocessing
来加速我的代码。 我已经设法做了一个基本的例子:
import multiprocessing
import numpy as np
import time
# import scipy.special
def compute_something(t):
a = 0.
for i in range(100000):
a = np.sqrt(t)
return a
if __name__ == '__main__':
pool_size = multiprocessing.cpu_count()
print "Pool size:", pool_size
pool = multiprocessing.Pool(processes=pool_size)
inputs = range(10)
tic = time.time()
builtin_outputs = map(compute_something, inputs)
print 'Built-in:', time.time() - tic
tic = time.time()
pool_outputs = pool.map(compute_something, inputs)
print 'Pool :', time.time() - tic
这很好,返回
Pool size: 8
Built-in: 1.56904006004
Pool : 0.447728157043
但如果我取消注释行import scipy.special
,我得到:
Pool size: 8
Built-in: 1.58968091011
Pool : 1.59387993813
我可以看到只有一个核心正在我的系统上工作。 事实上,从scipy包导入任何模块似乎都有这种效果(我已经尝试了几个)。
有任何想法吗? 我以前从未见过这样的案例,其中一个看似无害的导入可能会产生如此奇怪和意想不到的效果。
谢谢!
更新(1)
将scipy导入行移动到函数compute_something
部分改善问题:
Pool size: 8
Built-in: 1.66807389259
Pool : 0.596321105957
更新(2)
感谢@larsmans在不同的系统上进行测试。 使用Scipy v.0.12.0未确认问题。 将此查询移至scipy邮件列表并发布任何答案。
经过大量挖掘并在Scipy GitHub网站上发布问题后 ,我找到了解决方案。
在我开始之前,这是记录非常好这里 -我只是给出一个概述。
这个问题不仅关系到SciPy的,或与NumPy的版本,我用。 它起源于Numpy和Scipy用于各种线性代数例程的系统BLAS库。 您可以通过运行来确定Numpy链接到哪些库
python -c 'import numpy; numpy.show_config()'
如果您在Linux中使用OpenBLAS,您可能会发现CPU亲和性设置为1,这意味着一旦这些算法在Python中导入(通过Numpy / Scipy),您最多可以访问CPU的一个核心。 要在Python终端运行中测试这一点
import os
os.system('taskset -p %s' %os.getpid())
如果CPU亲和力返回f
的ff
,您可以访问多个内核。 在我的情况下,它会像那样开始,但在导入numpy或scipy.any_module时,它将切换为1
,因此我的问题。
我找到了两个解决方案:
更改CPU亲和力
您可以在main函数的顶部手动设置主进程的CPU关联,以便代码如下所示:
import multiprocessing
import numpy as np
import math
import time
import os
def compute_something(t):
a = 0.
for i in range(10000000):
a = math.sqrt(t)
return a
if __name__ == '__main__':
pool_size = multiprocessing.cpu_count()
os.system('taskset -cp 0-%d %s' % (pool_size, os.getpid()))
print "Pool size:", pool_size
pool = multiprocessing.Pool(processes=pool_size)
inputs = range(10)
tic = time.time()
builtin_outputs = map(compute_something, inputs)
print 'Built-in:', time.time() - tic
tic = time.time()
pool_outputs = pool.map(compute_something, inputs)
print 'Pool :', time.time() - tic
请注意,选择比核心数量高的值taskset
似乎并不重要-它只是使用最大可能数。
切换BLAS库
在上面链接的站点上记录的解决方案 基本上:安装libatlas并运行update-alternatives
将numpy指向ATLAS而不是OpenBLAS。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.