创建多处理阵列时出现分段错误

sh3*_*211 8 python numpy python-multiprocessing

我正在尝试使用多处理填充一个numpy数组,在这篇文章之后.我在Mac上运行得很好,但是当我将它移植到Ubuntu时,我会在很多时候遇到分段错误.

我已经将代码简化为以下最小的示例:

import numpy as np
from multiprocessing import sharedctypes

a = np.ctypeslib.as_ctypes(np.zeros((224,224,3)))
print("Made a, now making b")
b = sharedctypes.RawArray(a._type_, a)
print("Finished.")
Run Code Online (Sandbox Code Playgroud)

在Ubuntu 16.04上,使用Python 3.6.5和numpy 1.15.4(与我的Mac上相同的版本),我得到了输出

Made a, now making b
Segmentation fault (core dumped)
Run Code Online (Sandbox Code Playgroud)

现在,我可以稍微更改数组维度,在某些情况下它可以工作(例如,将第一个224更改为100并且它可以工作).但主要是它会出现故障.

有人可以提供任何见解吗?

我看到一篇关于2016年相关主题的帖子没有人回复,另一篇涉及我没有使用的指针.

PS-我是指定a为多维数组还是扁平数组(例如np.zeros(224*224*3))似乎没有任何区别.如果我更改数据类型(例如float to int),它似乎也没有区别; 它失败了.

还有一个更新:即使在原始帖子的代码中设置"size = 224",也会导致两个不同版本的numpy的Ubuntu机器出现seg故障,但在Mac上工作正常.

tel*_*tel 5

这更多的是猜测,而不是答案,但是由于底层数据缓冲区的垃圾回收,您可能会遇到问题。这可以解释为什么似乎要依赖于您要创建的数组的整体大小。

如果是这种情况,那么解决方法是将您创建的Numpy零数组分配给它自己的变量。这将确保通过创建缓冲区“有效” RawArray。代码如下:

zs = np.zeros((224,224,3))
a = np.ctypeslib.as_ctypes(zs)
print("Made a, now making b")
b = sharedctypes.RawArray(a._type_, a)
print("Finished.")
Run Code Online (Sandbox Code Playgroud)

我现在只有一台Mac,因此无法亲自测试。


Ant*_*ile 5

其他分析和根本原因修复。

如上所述,这是垃圾收集错误的结果,这给了我一个关于如何修复它的提示。

通过保持对原始np.zeros对象的引用,避免了错误。这意味着(对我而言)原始对象的集合破坏了结果数组。

查看as_ctypes(取自c52543e4a)的实现

def as_ctypes(obj):
    """Create and return a ctypes object from a numpy array.  Actually
    anything that exposes the __array_interface__ is accepted."""
    ai = obj.__array_interface__
    if ai["strides"]:
        raise TypeError("strided arrays not supported")
    if ai["version"] != 3:
        raise TypeError("only __array_interface__ version 3 supported")
    addr, readonly = ai["data"]
    if readonly:
        raise TypeError("readonly arrays unsupported")
    tp = _ctype_ndarray(_typecodes[ai["typestr"]], ai["shape"])
    result = tp.from_address(addr)
    result.__keep = ai
    return result
Run Code Online (Sandbox Code Playgroud)

很明显,原作者想到了这一点(分配.__keep以维护对原始对象的引用)。但是,他们似乎需要保留对原始对象的引用。

我写了一个补丁来做到这一点:

-        result.__keep = ai
+        result.__keep = obj
Run Code Online (Sandbox Code Playgroud)