使用函数指针指向没有gil的类的方法

时间:2016-01-19 14:08:49

标签: cython

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

我们说我得到了一个数值积分例程或类似的函数指针作为输入

ctypedef double (* someFunctionPointer) (double tt) nogil

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

现在我的每个集成点实际上都是一个更大的"模拟(许多参数等我加载/设置/输入或其他),这是在一个类中实现的。所以我最初的做法是做

之类的事情
cdef class SimulationClass:

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

我虽然可以随手提供" simulationFunctionPointer" to" integrationRoutine"没关系由于自我论证,这当然不起作用。

我所有的解决方案都需要

  • 不使用cdef类,而是使用类似C结构的东西(如果SimulationClass引用了很多其他类,参数等,那就很棘手)
  • 使用gil执行某些操作(因为我想使用SimulationClass;我编写了一些独立的函数,它将SimulationClass作为void *,但我需要再次将它转换为SimulationClass,这需要gil)

任何建议或想法如何解决这个问题?我的第一种方法是否可以用于其他语言,如C ++?

干杯

1 个答案:

答案 0 :(得分:4)

您可以在需要GIL的块周围使用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" ,然后在占用大部分运行时间的重要内部块周围使用nogil。举一个简单的例子

do_long_calculation

如果do_long_calculation中的do_long_calculation部分的运行时间比您设置的部分长,并且通过模拟(可以与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! 并行运行,但不能与自身同时运行)效率很高。

关于将绑定方法转换为函数指针的另一个小注释:你在Cython中真的很难做到这一点。我最好的工作是使用ctypes(或者也可能是cffi)可以将任何Python可调用的函数转换为函数指针。他们这样做的方式似乎涉及一些你可能不想复制的运行时代码生成。您可以将此方法与Cython结合使用,但它可能会给函数调用增加一些开销(因此请确保$computername=$args[0] if ($args -eq $null) { $computername = Read-Host "enter computer name" } Get-ADComputer -Id $computername -Properties * | select name,description 实际上很长!)

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

numbers = []

def easy_mode():
    with open("aa.txt","r") as f:
        for i in range(9):
            numbers.append(f.readline().strip())
        print(numbers)

 from random import randint

 for i in range(9):
    print(numbers[randint(0,8)])