use*_*489 5 python numpy cython
我想创建一个Cython函数,它读取一个数组并返回一个数组.这个函数将从其他cdef函数中调用,而不是python def函数.这就是我所拥有的.
在我的.pxd文件中:
cdef int[:] array_test(double *x) nogil
Run Code Online (Sandbox Code Playgroud)
在我的.pyx文件中:
cdef inline int[:] array_test(double *x) nogil:
cdef int output[2]
output[0]=1
output[1]=9
return output
Run Code Online (Sandbox Code Playgroud)
但是当我编译时,我得到错误:"不允许没有gil的操作"有人可以帮忙吗?
可能存在一个误解:此函数不返回c数组而是返回内存视图切片.你不必相信我,你可以通过删除nogil和调用cython 来检查它.在创建的*.c文件中,您可以看到函数的C签名,__Pyx_memviewslice这是重要的部分:
static CYTHON_INLINE __Pyx_memviewslice __pyx_f_4file_array_test(CYTHON_UNUSED double *__pyx_v_x)
Run Code Online (Sandbox Code Playgroud)
这个内存视图是一个Python对象,所以它必须更新它的引用计数器(至少在创建时),因此需要全局解释器锁(否则另一个线程可能会破坏这个非常计数器,并且该对象不会被破坏或销毁虽然它仍在某处使用) - 这就是你看到"不允许没有gil的操作" - 错误消息的原因.
所以你至少有三个选择:
int *res = (int *) malloc(2*sizeof(int)).这是快速的,缺点:你必须自己管理内存.std::vector<int>,优点是,您不必再管理内存,但需要切换到c ++.可能性1.的改进是仅在需要的最后一行获取gil(这对于这个例子没有太大的区别,但可能对于实际代码而言):
cdef inline int[:] array_test(double *x) nogil:
cdef int output[2]
output[0]=1
output[1]=9
with gil:
return output
Run Code Online (Sandbox Code Playgroud)
正如OP提出的那样,另一种可能性是将函数的签名更改为:
cdef inline void array_test(double *x, int[:] output) nogil:
Run Code Online (Sandbox Code Playgroud)
这里的技巧:功能array_test不再创建结果内存视图切片,因此不必进行引用计数 - 这使得"nogil"成为可能.顺便说一下,这是唯一可能的,因为对于'cdef cdefPy_INCREF/Py_INCREF/Py_DECREFPy_DECREF def`-函数).
有一些小的缺点,比如调用def变得更麻烦,调用者必须有gil才能创建array_test内存视图.但它的优点还在于,调用者可以确定应该在哪种数据结构中存储结果(numpy数组或其他东西).
| 归档时间: |
|
| 查看次数: |
948 次 |
| 最近记录: |