将多处理与Cython结合使用时发生错误

时间:2018-11-24 18:36:20

标签: python multiprocessing cython

我写了一个使用Cython实用程序模块的类。然后,我尝试使用Multiprocessing加快处理速度,以同时处理该类的多个实例,但出现错误。 Error sending result: '(0, <MemoryView of 'ndarray' at 0x19de04081f0>)'. Reason: 'TypeError('no default __reduce__ due to non-trivial __cinit__',)'我曾经考虑编写一个__reduce__函数,但是我所看到的一切都与酸洗类有关,与方法或模块无关。我还研究了编写__cinit__方法的过程,但看不到的似乎更重要。

下面是产生错误的程序包和模块布局的简化表示(实际上将要处理数百个DNG对象,每个对象都引用一个唯一的20ish MB文件,而ljpeg实际上有数百行,称为十行)每个DNG最多可以重复数百次)。在该示例中,可以通过删除数组类型声明来修复错误,但是如果我这样做,那么在性能上,性能损失将比多处理增益大几个数量级。

可以解决此问题而不显着降低它的速度或进行重大重构吗?如果可以,如何解决?

sequence.py

import multiprocessing

import numpy as np

from dng import DNG


def test_decode():
    input_file = np.zeros(3000, dtype=np.intc)

    pool = multiprocessing.Pool()
    tasks = []

    for i in range(10):
        task = pool.apply_async(thread, (i, input_file))
        tasks.append(task)

    pool.close()
    pool.join()

    for task in tasks:
        print(task.get())


def thread(i, input_file):
    dng = DNG(input_file)
    return i, dng.image


if __name__ == '__main__':
    test_decode()

dng.py

import numpy as np

import ljpeg


class DNG:
    def __init__(self, input_file):

        self.image = ljpeg.decode(input_file)

ljpeg.pyx

cpdef int[:] decode(int[:] encoded_image):
    encoded_image = __bar(encoded_image, 10000, 1000)
    return encoded_image


cdef int[:] __bar(int[:] array, int i, int ii):
    for j in range(i):
        for jj in range(ii):
            array = __foo(array)
    return array


cdef int[:] __foo(int[:] array):
    array[0] += 1
    return array

输出:

Traceback (most recent call last):
  File "F:/Documents/Python/threading_multi/sequence.py", line 31, in <module>
    test_decode()
  File "F:/Documents/Python/threading_multi/sequence.py", line 22, in test_decode
    print(task.get())
  File "C:\Python36\lib\multiprocessing\pool.py", line 644, in get
    raise self._value
multiprocessing.pool.MaybeEncodingError: Error sending result: '(0, <MemoryView of 'ndarray' at 0x19de04081f0>)'. Reason: 'TypeError('no default __reduce__ due to non-trivial __cinit__',)'

Process finished with exit code 1

1 个答案:

答案 0 :(得分:1)

我非常确定这是将每个线程生成的内存视图返回到主线程的错误(因为无法对内存视图进行腌制)。但是,memoryview本身包装了另一个可能被腌制的Python对象。

实际上不需要指定decode的返回类型(或将其设为cpdef),因为它仅是从Python调用的。在decode的末尾,返回memoryview的.base以获取其包装的基础对象:

def decode(int[:] encoding_image):
    # ...
    return encoding_image.base