我想将本地定义的python函数与gsl库集成。为此,我用Cython实现了以下代码(例如高斯-勒让德正交(:
pxd文件:
cdef extern from "gsl/gsl_math.h":
ctypedef struct gsl_function:
double (* function) (double x, void * params) nogil
void * params
cdef extern from "gsl/gsl_integration.h":
gsl_integration_glfixed_table * gsl_integration_glfixed_table_alloc(size_t n) nogil
double gsl_integration_glfixed(gsl_function *f, double a, double b, gsl_integration_glfixed_table * t) nogil
void gsl_integration_glfixed_table_free(gsl_integration_glfixed_table *t) nogil
cdef double int_gsl_GaussLegendre(double func(double, void *) nogil, void * p, double xmin, double xmax) nogil
和pyx文件:
cdef size_t size_GL=1000
cdef double int_gsl_GaussLegendre(double func(double, void *) nogil, void * p, double xmin, double xmax) nogil:
cdef double result, error;
cdef gsl_integration_glfixed_table * W
cdef gsl_function F
W = gsl_integration_glfixed_table_alloc(size_GL)
F.function = func
F.params = p
result = gsl_integration_glfixed(&F, xmin, xmax, W)
gsl_integration_glfixed_table_free(W)
return result
这段代码适用于我的Cython代码中声明的任何C函数。当然,当我将python函数作为参数传递时,这将失败。我在python中的脚本:
def gsl_integral(py_func, xmin, xmax, args=()):
cdef size_t sizep = <int>(args.size)
cdef double[:] params = np.empty(sizep, dtype=np.double)
for i in range(0,sizep):
params[i]=args[i]
cdef gsl_function F
F.function = py_func
F.params = params
其返回:";无法将Python对象转换为"double(*((double,void*(nogil";
如果我改为使用:
def gsl_integral(py_func, xmin, xmax, args=()):
cdef size_t sizep = <int>(args.size)
cdef double[:] params = np.empty(sizep, dtype=np.double)
for i in range(0,sizep):
params[i]=args[i]
cdef gsl_function F
F.function = <double *>py_func
F.params = params
其返回:";Python对象不能被强制转换为基元类型"的指针;
我已经看到我可以将我的cython函数包装成一个类(将c函数作为参数传递给cython中的python函数(,但我不太确定在这种情况下如何做到这一点(加上这个例子对我不起作用。(作为一种变通方法,我一直在向cython传递两个数组x和f(x(,后者用我的本地python f估计,为了定义一个我可以稍后集成的gsl样条曲线,但这一点都不优雅。还有其他办法吗?我想在没有GIL 的情况下使用GSL集成
非常感谢,罗曼
您的基本前提有几个基本问题:
- C函数指针没有任何状态。Python可调用对象确实具有状态。因此,C函数指针没有的空间来存储调用Python函数所需的信息
- 如果您正在调用Python可调用对象,则不能释放GIL,因为您必须具有GIL才能执行该对象
此答案概述了您的选项(C++std::function
选项不适用于此处(。本质上,你可以选择
- 使用
ctypes
从Python函数生成函数指针(它在运行时通过生成破解代码来实现这一点——这在标准C中是不可能的( - 或者编写一个具有适当签名的
cdef
函数作为函数指针传递,并将可调用的Python作为void*
参数的一部分传递给它
我推荐后者,但两者都不是很好的选择。