我写了一个使用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
答案 0 :(得分:1)
我非常确定这是将每个线程生成的内存视图返回到主线程的错误(因为无法对内存视图进行腌制)。但是,memoryview本身包装了另一个可能被腌制的Python对象。
实际上不需要指定decode
的返回类型(或将其设为cpdef
),因为它仅是从Python调用的。在decode
的末尾,返回memoryview的.base
以获取其包装的基础对象:
def decode(int[:] encoding_image):
# ...
return encoding_image.base