在没有 gil 的情况下使用指向 类 方法的函数指针

Using function pointers to methods of classes without the gil

我的部分工作需要大量计算,但它们通常相当简单,原则上可以很容易地与 Cython 的 prange 并行完成,需要 nogil。但是,考虑到我试图编写我的 Cython 代码,重点是将 cdef classes 作为构建块,我遇到了一个问题。

假设我有一个以函数指针作为输入的数值积分程序或类似程序

ctypedef double (* someFunctionPointer) (double tt) nogil

cdef double integrationRoutine(someFunctionfointer ff) nogil:
    # Doing something
    # ...
    return result

现在我的每个集成点实际上是一个 "larger" 模拟(很多参数等等我 load/set/input 或其他),它是在 class 中实现的。所以我最初的方法是做类似

的事情
cdef class SimulationClass:

    cdef double simulationFunctionPointer(SimulationClass self, double tt) nogil:
        # ...

虽然我可以将 "simulationFunctionPointer" 交给 "integrationRoutine" 并且会很好。由于 self 参数,这当然不起作用。

我所有的解决方法都需要

有什么建议或想法可以解决这个问题吗?我的第一种方法是否适用于 C++ 等其他语言?

干杯

您可以在需要 GIL 的块周围使用 with gil:,然后在将占用您大部分 运行 时间的重要内部块周围使用 with nogil:。举个简单的例子

from cython.parallel import prange

cdef class Simulation:
    cdef double some_detail

    def __cinit__(self,double some_detail):
        self.some_detail = some_detail

    def do_long_calculation(self, double v):
        with nogil:
            pass # replace pass with something long and time-consuming
        return v*self.some_detail


def run_simulations(int number_of_simulations):
    cdef int n
    for n in prange(number_of_simulations,nogil=True):
        with gil: # immediately get the gil back to do the "pythony bits"
            sim = Simulation(5.3*n)
            sim.do_long_calculation(1.2) # and release again in here"

do_long_calculation 运行 秒中提供的 nogil 部分比您设置和通过模拟的部分更长(可以 运行 与 do_long_calculation,但不是自身)这是相当有效的。


关于将绑定方法转换为函数指针的附加小评论:您在 Cython 中真的很难做到这一点。我拥有的最佳解决方法是使用 ctypes(或者也可能是 cffi),它 可以 将任何 Python 可调用函数转换为函数指针。他们这样做的方式似乎涉及一些您可能不想复制的 运行 时间代码生成。您可以将此方法与 Cython 结合使用,但它可能会给函数调用增加一些开销(因此请确保 do_long_calculation 实际上很长!)

以下作品(归功于http://osdir.com/ml/python-cython-devel/2009-10/msg00202.html

import ctypes
# define the function type for ctypes
ftype = ctypes.CFUNCTYPE(ctypes.c_double,ctypes.c_double)

S = Simulation(3.0)
f = ftype(S.do_long_calculation) # create the ctypes function pointer

cdef someFunctionPointer cy_f_ptr = (<someFunctionPointer*><size_t>ctypes.addressof(f))[0] # this is pretty awful!