Python - 使用 joblib 循环并行化

Python - Loop parallelisation with joblib

我需要一些帮助来准确理解我做了什么/为什么我的代码没有像我期望的那样 运行ning。

我已经开始使用 joblib 来尝试通过 运行并行(大)循环来加速我的代码。

我是这样用的:

from joblib import Parallel, delayed
def frame(indeces, image_pad, m):

    XY_Patches = np.float32(image_pad[indeces[0]:indeces[0]+m, indeces[1]:indeces[1]+m,  indeces[2]])
    XZ_Patches = np.float32(image_pad[indeces[0]:indeces[0]+m, indeces[1],                  indeces[2]:indeces[2]+m])
    YZ_Patches = np.float32(image_pad[indeces[0],                 indeces[1]:indeces[1]+m,  indeces[2]:indeces[2]+m])

    return XY_Patches, XZ_Patches, YZ_Patches


def Patch_triplanar_para(image_path, patch_size):

    Image, Label, indeces =  Sampling(image_path)

    n = (patch_size -1)/2
    m = patch_size

    image_pad = np.pad(Image, pad_width=n, mode='constant', constant_values = 0)

    A = Parallel(n_jobs= 1)(delayed(frame)(i, image_pad, m) for i in indeces)
    A = np.array(A)
    Label = np.float32(Label.reshape(len(Label), 1))
    R, T, Y =  np.hsplit(A, 3)

    return R, T, Y, Label

我一直在试验 "n_jobs",希望增加它可以加快我的功能。但是,当我增加 n_jobs 时,速度会显着降低。当 运行 在没有 "Parallel" 的情况下使用此代码时,事情会变慢,直到我将作业数从 1 增加。

为什么会这样?我了解到我 运行 的工作越多,脚本越快?我用错了吗?

谢谢!

可能你的问题是因为image_pad是一个大数组。在您的代码中,您使用的是 joblib 的默认 multiprocessing 后端。这个后端创建了一个工作池,每个工作池都是一个 Python 进程。然后将函数的输入数据复制 n_jobs 次并广播给池中的每个工作人员,这可能会导致严重的开销。引用 joblib 的文档:

By default the workers of the pool are real Python processes forked using the multiprocessing module of the Python standard library when n_jobs != 1. The arguments passed as input to the Parallel call are serialized and reallocated in the memory of each worker process.

This can be problematic for large arguments as they will be reallocated n_jobs times by the workers.

As this problem can often occur in scientific computing with numpy based datastructures, joblib.Parallel provides a special handling for large arrays to automatically dump them on the filesystem and pass a reference to the worker to open them as memory map on that file using the numpy.memmap subclass of numpy.ndarray. This makes it possible to share a segment of data between all the worker processes.

Note: The following only applies with the default "multiprocessing" backend. If your code can release the GIL, then using backend="threading" is even more efficient.

所以如果你是这种情况,你应该切换到线程后端,如果你能够在调用 frame 时释放全局解释器锁,或者切换到 [=12= 的共享内存方法].

docsjoblib 提供了一个可能有用的自动 memmap 转换。

您 运行 遇到的问题很可能是 python 编译器本质的一个基本问题。

如果您阅读“https://www.ibm.com/developerworks/community/blogs/jfp/entry/Python_Is_Not_C?lang=en”,您可以从专门优化和并行化 python 代码的专业人员那里了解到,迭代大循环对于 python 线程来执行。因此,生成更多遍历数组的进程只会减慢速度。

但是 - 有些事情可以做。

Cython and Numba compilers are both designed to optimise code that is similar to C/C++ style (i.e. your case) - in particular Numba's new @vectorise 装饰器允许标量函数以并行方式接受大型数组并在大型数组上应用操作 (target=Parallel)。

我对您的代码的理解还不足以给出一个实现示例,但请试试这个!这些编译器,以正确的方式使用,在过去为我的并行进程带来了 3000,000% 的速度提升!