首页 文章

如果导入PySide,python子进程在numpy点上崩溃

提问于
浏览
9

当使用带有numpy和PySide导入的pytnon多处理池时,我的机器上发生了这种非常特殊的悬挂 . 这是我迄今为止在生活中看到的最纠结的错误:)以下代码:

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]

我可以采取一些神奇的修改来防止悬挂:

  • 如果减少进入'dot'的数组形状(例如从128到127)

  • (!)如果你将进入'dot'的数组的形状从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)]

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

Update :我缩小了pylab import以导入带有pyside后端的matplotlib,并更新了要运行的代码 .

Update :我正在修改帖子只导入PySide而不是:

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

Update :初步统计显示这是一个仅限Mac的问题 . 有3人在Ubuntu上工作,2人在Mac上挂了它 .

Update :在点操作之前打印(os.getpid())给了我一个pid,我没有't see in ' top'显然意味着它崩溃并且多处理等待一个死进程 . 出于这个原因,我无法附加调试器 . 我相应地编辑了主要问题 .

3 回答

  • 7

    我认为这是多处理模块的一个问题 .

    请尝试使用以下代码 .

    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!')
    
  • 0

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

    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:]
    
  • 0

    这是numpy为 dot 使用的一些BLAS库的一般问题 .

    已知使用GNU Openmp构建的Apple Accelerate和OpenBlas在fork的两侧都不安全(父进程和子进程多处理创建) . 他们将陷入僵局 .

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

    • 使用基于pthreads的netlib BLAS,ATLAS或git master OpenBlas(2.8.0不起作用)

    • 使用python 3.4及其新的多处理 spawnforkserver 启动方法

    • 使用线程而不是多处理,numpy为最昂贵的操作释放gil,因此您可以在典型的桌面计算机上存档正常的线程加速

相关问题