mac*_*low 3 python parallel-processing numpy cython
我想并行化迭代,其中评估了许多cython实例实例,结果存储在全局numpy数组中:
for cythonInstance in myCythonInstances:
success = cythonInstance.evaluate(someConstantGlobalVariables,) # very CPU intense
if success == False:
break
globalNumpyArray[instanceSpecificLocation] = cythonInstance.resultVector[:]
Run Code Online (Sandbox Code Playgroud)
实例评估的结果彼此独立.实例之间没有任何类型的交互,除了结果写入相同的全局数组,但是在固定的,预定的和独立的位置.如果一个评估失败,则必须停止迭代.
据我所知,2种可能性是可能的:1)使用多处理包2)制作cython函数并使用prange/openmp.
我根本没有并行化的经验.哪种解决方案更可取,还是有更好的替代方案?谢谢!
我建议joblib与threading后端一起使用。Joblib 是一个非常好的并行化 for 循环的工具。Joblib
线程在这里比多处理更受欢迎,因为多处理有很多开销。当需要进行大量并行计算时,这是不合适的。然而,结果存储在一个列表中,然后您可以将其转换回 numpy 数组。
from joblib import Parallel, delayed
def sim(x):
return x**2
if __name__ == "__main__":
result = Parallel(n_jobs=-1, backend="threading", verbose=5) \
(delayed(sim)(x) for x in range(10))
print result
Run Code Online (Sandbox Code Playgroud)
结果
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Run Code Online (Sandbox Code Playgroud)
如果可以,请使用Cython:
该prange语法非常相似range.它允许您采用编写Python循环的简单开发路径 - >将其转换为Cython - >将其转换为并行循环.希望每次所需的更改都很小.相比之下,多处理需要您将循环内部作为一个函数,然后设置ppols,因此它不那么熟悉.
OpenMP/Cython线程的开销很低.相反,多处理模块的开销相对较高("进程"通常比"线程"慢).
多处理在Windows中受到很大限制(一切都必须是可选择的).这经常是一件非常麻烦的事.
您应该使用多处理时有一些特定情况:
您发现需要获得很多GIL - 多处理不共享GIL因此不会减慢速度.如果你只是需要偶尔获得GIL,那么with 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
Run Code Online (Sandbox Code Playgroud)
我不建议使用Cython类的原因是1)你不能创建它们或在没有GIL的情况下索引它们的列表(出于引用计数的原因)和2)包括Cython类的Python对象似乎不是允许是本地线程.看Cython parallel prange - 线程局部性?举例说明这些问题.(原来我不知道成为当地人的限制)
with_gil涉及的开销不一定很大,所以如果这个设计最有意义,那就试试吧.查看您的CPU使用情况将告诉您它的并行化程度.
铌.即使您使用的是Cython而不是Python线程模块,这组答案中的大部分优缺点仍然适用.不同之处在于您通常可以避免使用Cython中的GIL(因此使用线程的一些缺点不那么重要).