奇怪的多处理块导入 Numba 函数

Weird multiprocessing block importing Numba function

环境

初始设置(工作正常)

两个文件main.pynumbamodule.py:

main.py

它为 运行 execute_numba 函数生成 2 个进程。

import time
from importlib import import_module
from multiprocessing import Process


def execute_numba(name):
    # Import the function
    importfunction = 'numbamodule.numba_function'
    module = import_module(importfunction.split('.')[0])
    function = getattr(module, importfunction.split('.')[-1])
    while True:
        print(str(name) + ' - executing Numba function...')
        # Execute the function
        function(10)
        time.sleep(0.1)


if __name__ == '__main__':
    processes = [Process(target=execute_numba, args=(i,)) for i in range(2)]
    [p.start() for p in processes]
    time.sleep(1)
    [p.terminate() for p in processes]

numbamodule.py

其中定义了一个简单的函数numba_function:

import numba


@numba.jit()
def numba_function(x):
    total = 0
    for i in range(x):
        total += i
    return total

我可以 运行 main.py 脚本并查看两个进程打印:

$ python main.py
0 - executing Numba function...
1 - executing Numba function...
0 - executing Numba function...
1 - executing Numba function...
0 - executing Numba function...
1 - executing Numba function...
[...]

打破它

我打破它的方式有点奇怪,但这是我在尝试最小化可重现的测试用例时偶然发现的。请告诉我您是否也可以重现相同的行为。

main.py 中,我只是在最后一个 Process 导入之后添加了一个建议的(波纹管)导入(即:取消注释一行并尝试):

import time
from importlib import import_module
from multiprocessing import Process

#
# Adding one of the import lines bellow results in a block...
# (you may need to install the packages first in the virtual environment)
#
#import matplotlib
#import Pyro4
#import scipy
#import dill


def execute_numba(name):
# [...]

然后一个进程可能会阻塞在 execute_numba 函数处(特别是在 import_module() 调用处):

$ python main.py 
1 - executing Numba function...
1 - executing Numba function...
1 - executing Numba function...
1 - executing Numba function...
1 - executing Numba function...
1 - executing Numba function...
[...]

对我来说,matplotlibPyro4 导入 "work" 是最好的。我什至无法获得 100% 的 运行s... :-/

请注意,我只是添加了一个导入行,而不是实际使用包。其他一些外部导入也会导致阻塞,但我发现上面提出的 "work" 最好(阻塞最多)。

发生了什么事?

首先,你能重现同样的行为吗? (对非虚拟化 GNU/Linux 机器特别感兴趣)

我不知道如何调试它或为什么会发生这种情况。有什么想法吗?

添加一个随机 import xxx 触发块这一事实让我感到害怕,对我来说毫无意义。这是否取决于 timing/delays,这就是为什么有些进口会破坏它而另一些则不会?

备注

更新

这里是官方PythonDocker环境的复现。 Dockerfile 紧随其后(放入您的 .py 文件)。

FROM python:3.5

RUN pip install numba matplotlib pyro4

ADD . /opt
WORKDIR /opt

CMD python main.py

然后:

docker build -t so-44764520 .
docker run --rm -it so-44764520

两者的工作方式相同,没有 "working" 导入,matplotlibPyro4,并且在 main.py 中有它们。

这仅适用于 matplotlib 调试,确实是猜测,但可能会帮助您缩小问题范围。

您可以在包含 matplotlib 时启动您的程序:

python main.py --verbose-helpful

显示 matplotlib 初始化时的调试输出。由于这听起来像是只存在于您的特定系统上的问题,因此以交互模式启动的方式配置的 matplotlibrc 可能存在一些配置问题。

以下是可用调试模式的概述: https://matplotlib.org/users/customizing.html

这似乎是一个 Numba 错误,已在 issue 2431 中确认。

现在好像修复了。如果遇到此问题,请更新 numballvmlite 安装。如果这不能解决问题,您可能应该在该问题中添加评论以重新打开它。

正如@stuartarchibald 评论的那样:

[...] it looks like one processed is blocked is because it has in actual fact segfaulted [...]

[...] Segfaults appearing from this location are almost always due to threads performing concurrent operations inside LLVM, or some issue to do with installing functions during Numba's initialisation sequence. [...]

[...] cannot reproduce any more with llvmlite==0.22.0dev0 and numba==0.37.0.dev [...]