【问题标题】:python child process crashes on numpy dot if PySide is imported如果导入 PySide,python 子进程会在 numpy dot 上崩溃
【发布时间】:2014-07-20 18:26:33
【问题描述】:

当我使用 pytnon 多处理池并导入 numpy 和 PySide 时,我的机器上发生了这种非常奇怪的挂起。这是迄今为止我见过的最纠结的bug:)如下代码:

import numpy as np
import PySide


def hang():
    import multiprocessing
    pool = multiprocessing.Pool(processes = 1)
    pool.map(f, [None])


def f(ignore):
    print('before dot..')
    np.dot(np.zeros((128, 1)), np.zeros((1, 32)))
    print('after dot.')


if __name__ == "__main__":
    hang()
    print('success!')

仅在“点之前”挂起打印。但它应该打印出来

before dot..
after dot.
success!

我不是 gdb 专家,但看起来 gdb 显示进程在“np.dot”行上退出(或崩溃):

[Inferior 1 (process 2884) exited normally]

我可以做几个神奇的修改来防止挂起:

  • 如果您减小进入“点”的数组形状(例如,从 128 到 127)
  • (!)如果您将进入“点”的数组的形状从 128 增加到 256
  • 如果您不使用多处理并只运行函数“f”
  • (!!!) 如果您注释掉代码中未使用的 PySide 导入

感谢任何帮助!

包版本:

numpy=1.8.1 或 1.7.1 PySide=1.2.1 或 1.2.2

Python 版本:

Python 2.7.5(默认,2013 年 9 月 12 日,21:33:34) [GCC 4.2.1 兼容 Apple LLVM 5.0 (clang-500.0.68)] 达尔文

Python 2.7.6(默认,2014 年 4 月 9 日,11:48:52) [GCC 4.2.1 兼容 Apple LLVM 5.1 (clang-503.0.38)] 达尔文

注意:在寻找信息时,我简化了原始代码并提出了一些问题。但是这里有一堆更新,可以为可能遇到此错误的其他人保留历史记录(例如,我从 matplotlib 开始,而不是 pyside)

更新:我将 pylab 导入范围缩小到使用 pyside 后端导入 matplotlib 并更新了要运行的代码。

更新:我正在修改帖子以仅导入 PySide 而不是:

import matplotlib
matplotlib.use('qt4agg')
matplotlib.rcParams['backend.qt4']='PySide'
import matplotlib.pyplot

更新:初步统计显示,这是一个仅限 Mac 的问题。 3 个人在 Ubuntu 上运行,2 个人在 Mac 上运行。

更新:点操作之前的 print(os.getpid()) 给了我在“顶部”中看不到的 pid,这显然意味着它崩溃并且多处理等待死进程。出于这个原因,我无法将调试器附加到它。我相应地编辑了主要问题。

【问题讨论】:

  • 将 python 更新到 2.7.6 没有帮助
  • 导入 import matplotlib.pyplot 而不是 pylab 没有帮助
  • 如果 matplotlib 后端不是“qt4agg”,则不会出现问题。所以看起来这里甚至涉及到 qt。
  • 它适用于我的:NumPy 1.8.0、Python 2.7、64 位...
  • 也无法重现。使用调试器查看挂起的位置怎么样?

标签: python numpy multiprocessing pyside


【解决方案1】:

我遇到了这个确切的问题。子进程使用 numpy.dot 时出现死锁。但是当我减小矩阵的大小时它会运行。因此,我没有在具有 156000 个浮点数的矩阵上进行点积,而是执行了 3 个每个 52000 个点积并将结果连接起来。我不确定最大限制是多少,以及它是否取决于子进程的数量、可用内存或任何其他因素。但是如果可以通过反复试验确定最大的没有死锁的矩阵,那么下面的代码应该会有所帮助。

def get_batch(X, update_iter, batchsize):
    curr_ptr = update_iter*batchsize
    if X.shape[0] - curr_ptr <= batchsize :
        X_i = X[curr_ptr:, :]
    else:
        X_i = X[curr_ptr:curr_ptr+batchsize, :]
    return X_i

def batch_dot(X, w, batchsize):
    y = np.zeros((1,))
    num_batches = X.shape[0]/batchsize
    if X.shape[0]%batchsize != 0:
        num_batches += 1
    for batch_iter in range(0, num_batches):
        X_batch = get_batch(X, batch_iter, batchsize)
        y_batch = X_batch.dot(w)
        y = np.hstack((y, y_batch))
    return y[1:]

【讨论】:

    【解决方案2】:

    这是 numpy 用于dot 的一些 BLAS 库的普遍问题。

    众所周知,使用 GNU Openmp 构建的 Apple Accelerate 和 OpenBlas 在分叉的两侧(父进程和子进程多处理创建)都不能安全使用。他们会陷入僵局。

    numpy 无法解决此问题,但有三种解决方法:

    • 使用基于 pthreads 的 netlib BLAS、ATLAS 或 git master OpenBlas(2.8.0 不起作用)
    • 使用 python 3.4 及其新的多处理 spawnforkserver 启动方法
    • 使用线程而不是多处理,numpy 为最昂贵的操作发布了 gil,这样您就可以在典型的台式机上存档不错的线程加速

    【讨论】:

    • 谢谢!线程不是一个选项 - 点操作只占用约 10% 的执行,所以线程并没有给我想要的加速。不幸的是,Python 3 也不是一个选择——我在协作环境中工作,我们选择了 Python 2.7。那么有人可以指出我如何更改 numpy 的 blas 实现吗?
    • 您是否有更多关于该问题的信息,任何参考资料?我有一个非常相似的挂起,但不是在numpy.dot,只是在numpy.zeros(分配2MB 左右)。我也有多个线程和一个通过多处理的子进程。 Python 2.7 与 Theano。
    • 我在 NumPy 问题跟踪器中找不到它,所以我打开了一个新的。共识几乎就是 jtaylor 上面所说的。 github.com/numpy/numpy/issues/5752
    【解决方案3】:

    我认为这是多处理模块的问题。

    尝试改用以下内容。

    import numpy as np
    import PySide
    
    
        def hang():
            import multiprocessing.dummy as multiprocessing
            pool = multiprocessing.Pool(processes = 1)
            pool.map(f, [None])
    
    
        def f(ignore):
            print('before dot..')
            np.dot(np.zeros((128, 1)), np.zeros((1, 32)))
            print('after dot.')
    
    
        if __name__ == "__main__":
            hang()
            print('success!')
    

    【讨论】:

    • 是的,多处理、pyside 和 blas numpy dot 的组合存在问题。如果您删除一个组件,它不会挂起(并且您的代码也不会挂起)。但是不清楚我该如何继续,我真的想要多处理:)
    • 只使用 multiprocessing.dummy 它使用线程而不是多线程进程。
    • 它不会避免 GIL 对吧?我尝试了线程,它对我的​​目的来说太慢了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多