繁体   English   中英

导入scipy会破坏Python中的多处理支持

[英]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亲和力返回fff ,您可以访问多个内核。 在我的情况下,它会像那样开始,但在导入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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM