并行化python:多处理与cython

我想并行化迭代,其中评估了许多cython实例实例,结果存储在全局numpy数组中:

for cythonInstance in myCythonInstances:
    success = cythonInstance.evaluate(someConstantGlobalVariables,) # very CPU intense
    if success == False:
        break
    globalNumpyArray[instanceSpecificLocation] = cythonInstance.resultVector[:]

实例评估的结果彼此独立.实例之间没有任何类型的交互,除了结果写入相同的全局数组,但是在固定的,预定的和独立的位置.如果一个评估失败,则必须停止迭代.

据我所知,有两种可能性:
1)使用多处理包
2)制作一个cython函数并使用prange / openmp.

我根本没有并行化的经验.哪种解决方案更可取,还是有更好的替代方案?谢谢!

最佳答案 如果可以,请使用Cython:

> prange语法非常类似于range.它允许您采用编写Python循环的简单开发途径 – >将其转换为Cython – >将其转换为并行循环.希望每次所需的更改都很小.相比之下,多处理需要您将循环内部作为一个函数,然后设置ppols,因此它不那么熟悉.
> OpenMP / Cython线程的开销很低.相反,多处理模块的开销相对较高(“进程”通常比“线程”慢).
>多处理在Windows中受到很大限制(一切都必须是可选择的).这经常是一件非常麻烦的事.

您应该使用多处理时有一些特定情况:

>你发现你需要获得很多GIL – 多处理不共享GIL所以不会减慢速度.如果你只需偶尔获得GIL,那么gil很小:Cython中的块通常不会让你减速太多,所以先试试吧.
>你需要同时做一堆完全不同的操作(即不适合prange循环的东西,因为每个线程真正运行单独的代码).如果是这种情况,Cython prange语法并不适合.

查看代码的注意事项是,如果可以的话,应该避免使用Cython类.如果你可以将它重构为一个更好的cdef函数调用(Cython类有时候仍然需要GIL).类似于以下的东西会运作良好:

cdef int f(double[:] arr, double loop_specific_parameter, int constant_parameter) nogil:
    # return your boolean to stop the iteration
    # modify arr
    return result

# then elsewhere
cdef int i
cdef double[:,:] output = np.zeros(shape)
for i in prange(len(parameters_to_try),nogil=True):
   result = f(output[i,:],parameters_to_try[i],constant_parameter)
   if result:
      break

我不建议使用Cython类的原因是1)你不能创建它们或在没有GIL的情况下索引它们的列表(出于引用计数的原因)和2)包括Cython类的Python对象似乎不是允许是本地线程.有关问题的示例,请参见Cython parallel prange – thread locality?. (原来我不知道成为当地人的限制)

涉及的with_gil开销不一定很大,所以如果这个设计最有意义的话就试试吧.查看您的CPU使用情况将告诉您它的并行化程度.

铌.即使您使用的是Cython而不是Python线程模块,this set of answers中的大部分优缺点仍然适用.不同之处在于您通常可以避免使用Cython中的GIL(因此使用线程的一些缺点不那么重要).

点赞