Python 多处理 numpy.linalg.pinv 导致段错误

Python multiprocessing numpy.linalg.pinv cause segfault

我使用 python 中的多处理包编写了一个函数,并试图提高我的代码速度。

from arch.univariate import ARX, GARCH
from multiprocessing import Process
import multiprocessing
import time

def batch_learning(X, lag_array=None):
    """
    X is a time series array
    lag_array contains all possible lag numbers
    """
    # init a queue used for triggering different processes
    queue = multiprocessing.JoinableQueue()
    data = multiprocessing.Queue()

    # a worker called ARX_fit triggered by queue.get()
    def ARX_fit(queue):
        while True:
            q = queue.get()
            q.volatility = GARCH()
            print "Starting to fit lags %s" %str(q.lags.size/2)
            try:
                q_res=q.fit(update_freq=500)
            except:
                print "Error:...."
            print "finished lags %s" %str(q.lags.size/2)
            queue.task_done()
    # init four processes
    for i in range(4):
        process_i = Process(target=ARX_fit, name="Process_%s"%str(i),   args=(queue,))
        process_i.start()
    # put ARX model objects into queue continuously
    for num in lag_array:
        queue.put(ARX(X, lags=num))

    # sync processes here
    queue.join()   

    return

调用函数后:

batch_learning(a, lag_array=range(1,10))

然而它卡在了中间,我打印出如下消息:

Starting to fit lags 1
Starting to fit lags 3
Starting to fit lags 2
Starting to fit lags 4
finished lags 1
finished lags 2
Starting to fit lags 5
finished lags 3
Starting to fit lags 6
Starting to fit lags 7
finished lags 4
Starting to fit lags 8
finished lags 6
finished lags 5
Starting to fit lags 9

它永远运行,但在我的 Mac OS El Captain 上没有任何打印输出。然后使用 PyCharm 调试模式并感谢 Tim Peters 的建议,我成功地发现进程实际上意外退出了。在调试模式下,我可以确定它实际上是 arch 库使用的 numpy.linalg.pinv() 中的 svd 函数导致了这个问题。那么我的问题是:为什么?它适用于单进程 for-loop,但不能用于 2 个或以上进程。我不知道如何解决这个问题。这是一个麻木的错误吗?有人可以帮我一下吗?

这里没什么可继续的,而且代码缩进是错误的,所以很难猜出你到底在做什么。就我 可以 猜测的程度而言,如果 OS 以未引发 Python 异常的方式终止进程,则可能会发生您所看到的情况。

尝试一件事:首先列出 ps 四个 process_i 对象。然后在 queue.join() 之前添加:

while ps:
    new_ps = []
    for p in ps:
        if p.is_alive():
            new_ps.append(p)
        else:
            print("*********", p.name, "exited with", p.exitcode)
    ps = new_ps
    time.sleep(1)

所以大约每秒一次,这只是遍历工作进程列表以查看是否有任何进程(意外地!)死亡。如果一个(或多个)有,它会显示进程名称(您已经提供)和进程退出代码(由您的 OS 给出)。如果那触发了,那将是一个大线索。

如果none死了,那我们就得想

q_res=q.fit(update_freq=500)

"simply" 对于某些 q 个状态需要很长时间。

我必须自己回答这个问题并提供我的解决方案。感谢@Tim Peters 和@aganders 的帮助,我已经解决了这个问题。

当您在 Mac OS 上使用 numpy/scipy 库时,多处理通常会挂起,因为 Apple OS 中使用的 Accelerate Framework 是 OpenBlas numpy 的替代品建造在。很简单,为了解决类似的问题,你必须这样做:

  1. 卸载numpy和scipy(scipy需要匹配合适的numpy版本)
  2. 按照此 link 上的步骤使用 Openblas 重建 numpy。

  3. 重新安装 scipy 并测试您的代码以查看其是否有效。

请注意在 Mac OS 上测试您的多处理代码,当您 运行 您的代码时,最好将环境变量设置为 运行你的代码:

OPENBLAS_NUM_THREADS=1 python import_test.py

这样做的原因是 OpenBlas 默认为每个核心创建 2 个线程 运行,在这种情况下有 8 个线程 运行ning(每个核心 2 个线程),即使您设置4个进程。这为线程切换创建了一点开销。我测试了 OPENBLAS_NUM_THREADS=1 配置以限制每个内核上每个进程 1 个线程,它确实比默认设置更快。