在Cython中使用openMP:并行化内部循环

时间:2017-08-18 17:31:27

标签: python multithreading cython

(正如您将看到我对Python GIL和多线程IN PYTHON(或cython)等概念不太熟悉)

我在Cython中编写了一个函数,它由一个带有double for循环的代码片段组成,其中函数f被重复调用。

for i in range(I):
  for j in range(J):
    res=f(A[i],B[j])

我有一台带有4个CPU内核的机器,我希望不是第一个而是第二个循环并行化。 我找到了this wonderful website,但它没有处理内循环的情况,也没有详细说明。 所以在我看来我可以写:

for i in range(I):
  #In what case can I release the GIL safely ? Is that necessary at all ?
  with nogil, parallel(num_threads=4):
    for j in prange(J,shedule="dynamic"):
      res=f(A[i],B[j])

那会有用吗?我是否必须在两个循环之外放置nogil,以便它不会重复运行到其中并释放"捕获"这个GIL的事情?有人可以向我解释编写这些陈述背后的逻辑是什么,以便我能够概括到无法解决的问题。

1 个答案:

答案 0 :(得分:2)

释放和重新捕获GIL需要花费时间,并且设置并行循环也需要时间。出于这个原因,通常最好使最外面的环路成为平行环路。但是,如果您有充分的理由想要并行化内部循环,那么它将起作用,并且希望与f中包含的实际工作相比,成本应该很小。

释放GIL会阻止您访问Python变量并调用Python函数。键入的Cython变量,cdef函数和Cython内存视图都可以正常工作。尽可能远离with nogil:,您可以获得一个小小的加速。因此,如果可能的话,将它放在外环上,但是如果它不可能那么它就可以在你已经显示它的地方。

有必要向GIL发布prange循环。如果有必要,你可以在循环中回收它(with gil)但是只尝试在循环的小部分中执行此操作并且仅在需要时(需要GIL的代码不能与其他代码并行运行)需要GIL)。

对于并行代码,行res=f(A[i],B[j])稍微有点奇怪,因为只保存最后一个循环中的res。通常,您可以写入数组的元素(例如res[i,j]=f(A[i],B[j]))。但是,可能有充分的理由像你所展示的那样......

如果你尝试做一些需要GIL的事情,Cython会(通常)警告你,所以一个好主意是尝试并看看。