Python 使用Scipy进行大卷积的多处理没有加速

Python 使用Scipy进行大卷积的多处理没有加速,python,numpy,parallel-processing,scipy,multiprocessing,Python,Numpy,Parallel Processing,Scipy,Multiprocessing,我正在使用scipy.signal.correlate执行大型2D卷积。我有大量的数组需要操作,因此自然认为多处理.Pool会有所帮助。但是,使用以下简单设置(在4核cpu上)没有任何好处 import multiprocessing as mp import numpy as np from scipy import signal arrays = [np.ones([500, 500])] * 100 kernel = np.ones([30, 30]) def conv(array,

我正在使用
scipy.signal.correlate
执行大型2D卷积。我有大量的数组需要操作,因此自然认为
多处理.Pool
会有所帮助。但是,使用以下简单设置(在4核cpu上)没有任何好处

import multiprocessing as mp
import numpy as np
from scipy import signal

arrays = [np.ones([500, 500])] * 100
kernel = np.ones([30, 30])

def conv(array, kernel):
  return (array, kernel, signal.correlate(array, kernel, mode="valid", method="fft"))

pool = mp.Pool(processes=4)
results = [pool.apply(conv, args=(arr, kernel)) for arr in arrays]
将进程计数更改为{1,2,3,4}的时间大致相同(2.6秒+-.2)

会发生什么

会发生什么事

首先,我认为原因是底层FFT实现已经并行化了。虽然Python解释器是单线程的,但是可以从Python调用的C代码可以充分利用您的CPU

然而,scipy.correlate的底层FFT实现似乎是NumPy中的fftpack(从1985年编写的Fortran翻译而来),它看起来是单线程的

事实上,我运行了您的脚本并获得了相当高的CPU使用率。在我的计算机上有四个内核和四个进程,我得到了~2的加速比(对于2000x2000阵列,并且使用了从中更改的代码)

创建进程和与进程通信的开销消耗了CPU使用效率提高的部分好处


您仍然可以尝试优化数组大小,或者只计算一小部分相关性(如果不需要全部相关性),或者如果内核始终相同,则只需计算内核的FFT一次并重用它(这需要自己实现部分scipy.correlate)或者尝试单精度而不是双精度,或者使用CUDA在图形卡上进行关联。

我认为问题出在这一行:

results=[pool.apply(conv,args=(arr,kernel))用于数组中的arr]

Pool.apply是一个阻塞操作,在数组中的每个元素上运行
conv
,并在转到下一个元素之前等待,因此即使看起来是多处理,实际上也没有分发任何内容。您需要改用pool.map来获取所需的行为:

from functools import partial
conv_partial = partial( conv, kernel=kernel )
results = pool.map( conv_partial, arrays )

也可能是因为OPs缺乏加速比,所以bc的负载较低?生成新进程的时间可能会抵消任何优势(如果错误,请纠正我)是您真正的
内核
所有吗?
内核
仅用于此测试,而不是在我的实际应用程序中-但据我所知,这两种情况之间不应该有时间差?所有内核都是一个,更多信息。对于如此可观的大小(
30x30
),使用可分离内核会快得多