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

如果导入PySide,python子进程将在numpy点崩溃,python,numpy,multiprocessing,pyside,Python,Numpy,Multiprocessing,Pyside,当使用导入了numpy和PySide的pytnon多处理池时,我的机器上发生了一个非常奇怪的挂起。这是迄今为止我见过的最纠结的bug:)以下代码: import numpy as np import PySide def hang(): import multiprocessing pool = multiprocessing.Pool(processes = 1) pool.map(f, [None]) def f(ignore): print('bef

当使用导入了numpy和PySide的pytnon多处理池时,我的机器上发生了一个非常奇怪的挂起。这是迄今为止我见过的最纠结的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达尔文兼容苹果LLVM 5.0(clang-500.0.68)]

Python 2.7.6(默认值,2014年4月9日,11:48:52) [GCC 4.2.1达尔文兼容苹果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上运行


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

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

请尝试使用以下选项

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

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

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

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

  • 基于pthreads使用netlib BLAS、ATLAS或git master OpenBlas(2.8.0不起作用)
  • 使用Python3.4及其新的多处理
    spawn
    forkserver
    启动方法
  • 使用线程而不是多处理,numpy为最昂贵的操作发布了gil,因此您可以在典型的桌面计算机上归档适当的线程加速

    • 我遇到了这个问题。子进程使用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:]
      
      def get_batch(X,update_iter,batchsize):
      curr\u ptr=update\u iter*batchsize
      
      如果X.shape[0]-curr\u ptr将python更新为2.7.6无助于导入matplotlib.pyplot而不是pylab无助于导入matplotlib,则在matplotlib后端不是“qt4agg”时不会出现问题。。所以看起来这里甚至涉及到qt。它适用于我的:NumPy 1.8.0,Python 2.7,64位…也无法复制。使用调试器查看它挂起的位置如何?是的,将多处理、pyside和blas numpy dot结合起来是个问题。如果删除一个组件,它就不会挂起(代码也不会挂起)。但是,我不清楚如何继续,我真的想要多处理:)只使用多处理。dummy它使用线程而不是进程来多线程。它不会避免GIL,对吗?我试过穿线,对我来说太慢了。谢谢!线程不是一个选项-点操作只占执行的10%,所以线程并没有给我想要的速度。不幸的是,Python3也不是一个选项——我在一个协作环境中工作,我们选择了Python2.7。那么,有人能告诉我如何更改numpy的blas实现吗?您有关于这个问题的更多信息吗?有参考资料吗?我有一个非常类似的挂起,但不是在
      numpy.dot
      中,而是在
      numpy.zero
      中(分配2MB左右)。我还通过多处理拥有多个线程和一个子进程。Python2.7和Theano。我在NumPy问题跟踪器中找不到它,所以我打开了一个新的。这一共识与杰泰勒上面所说的差不多。