Python 将openMP与Cython一起使用:并行化内部循环

Python 将openMP与Cython一起使用:并行化内部循环,python,multithreading,cython,Python,Multithreading,Cython,(正如您将看到的,我不太熟悉Python GIL和Python(或cython)中的多线程等概念) 我用Cython编写了一个函数,它由一段代码组成,其中有一个double for循环,函数f被反复调用 for i in range(I): for j in range(J): res=f(A[i],B[j]) 我有一台有4个CPU核的机器,我想并行化的不是第一个而是第二个循环。 我发现,但它没有处理内部循环的情况,也没有详细说明。 所以在我看来,我可以写: for i in ra

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

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

for i in range(I):
  for j in range(J):
    res=f(A[i],B[j])
我有一台有4个CPU核的机器,我想并行化的不是第一个而是第二个循环。 我发现,但它没有处理内部循环的情况,也没有详细说明。 所以在我看来,我可以写:

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])

这样行吗?我是否必须将with nogil放在两个循环之外,这样它就不会重复运行,释放和“捕获”这个GIL东西?有人能给我解释一下写这些陈述背后的逻辑是怎样的,是什么,这样我就能够概括出一些看不见的问题。

释放和重新获得GIL需要时间成本,建立一个并行循环也需要时间成本。出于这个原因,通常最好将最外层的环设为平行环。然而,如果您有一个很好的理由来解释为什么您特别想要并行化内部循环,那么它将工作,并且希望与
f
中包含的实际工作相比,成本应该很小

释放GIL会阻止您访问Python变量和调用Python函数。类型化的Cython变量、
cdef
函数和Cython内存视图工作正常。使用nogil:将
放置到尽可能远的地方,您将获得一个小的加速。因此,如果可能的话,把它放在外环上,但是如果不可能,那么在你展示它的地方就可以了

有必要向GIL发布
prange
循环。如有必要,您可以在循环内回收它(
使用gil
),但尝试仅对循环的一小部分执行此操作,并且仅在需要时执行(需要gil的代码不能与其他需要gil的代码并行运行)

res=f(A[i],B[j])
对于并行代码来说有点奇怪,因为只有最后一个循环中的
res
会被保存。通常您会写入数组的元素(例如,
res[i,j]=f(A[i],B[j])
)。然而,像你所展示的那样做可能有很好的理由


Cython(通常)会警告你,如果你试图做一些需要GIL的事情,那么最好是试试看。

谢谢@DavidW绝对是个有趣的答案!显然,我有一个很好的理由不并行外环。我没有写代码的细节,res的东西很傻。我会改进我的问题。我投了赞成票,如果成功的话,我会接受的!