【问题标题】:Using openMP with Cython: parallelising an inner loop将 openMP 与 Cython 一起使用:并行化内部循环
【发布时间】:2017-08-18 17:31:27
【问题描述】:

(如你所见,我对 Python GIL 和 PYTHON(或 cython)中的多线程等概念不太熟悉)

我在 Cython 中编写了一个函数,该函数由一段代码和一个双 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])

这行得通吗?我是否必须将 with nogil 放在两个循环之外,这样它就不会反复运行它来释放和“捕获”这个 GIL 东西?有人可以向我解释一下编写此类语句的方式和逻辑是什么,以便我能够概括出看不见的问题。

【问题讨论】:

    标签: python multithreading cython


    【解决方案1】:

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

    释放 GIL 会阻止您访问 Python 变量和调用 Python 函数。键入的 Cython 变量、cdef 函数和 Cython 内存视图工作正常。将with nogil: 放在尽可能远的地方会稍微加快速度。因此,如果可能的话,把它放在外循环周围,但如果不可能,那么你展示它的地方就可以了。

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

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

    如果您尝试执行需要 GIL 的操作,Cython 会(通常)警告您,因此最好先尝试一下。

    【讨论】:

    • 感谢@DavidW 绝对有趣的答案!显然,我有充分的理由不并行化外循环。我没有写代码的细节,而 res 的东西很傻。我会稍微改进一下我的问题。我投了赞成票,如果可行,我会接受!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-19
    相关资源
    最近更新 更多