cdef double testB(double[:] x) nogil:
return x[0]
def test():
cdef double xx[2]
with nogil:
testB(xx)
# compiler error: Operation not allowed without gil
如果使用gil,它可以正常工作。
是因为当传入一个c数组时,它会创建一个内存视图,这样的创建动作实际上需要gil吗?那么内存视图不完全是一个c对象吗?
%%cython --annotate
cimport cython
cdef double testA(double[:] x) nogil:
return x[0]
cpdef myf():
cdef double pd[8]
cdef double[:] x = pd
testA(x)
cdef double[:] x = pd
编译为:
__pyx_t_3 = __pyx_format_from_typeinfo(&__Pyx_TypeInfo_double);
__pyx_t_2 = Py_BuildValue((char*) "(" __PYX_BUILD_PY_SSIZE_T ")", ((Py_ssize_t)8));
if (unlikely(!__pyx_t_3 || !__pyx_t_2 || !PyBytes_AsString(__pyx_t_3))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_1 = __pyx_array_new(__pyx_t_2, sizeof(double), PyBytes_AS_STRING(__pyx_t_3), (char *) "fortran", (char *) __pyx_v_pd);
if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_t_4 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(((PyObject *)__pyx_t_1));
if (unlikely(!__pyx_t_4.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
__pyx_v_x = __pyx_t_4;
__pyx_t_4.memview = NULL;
__pyx_t_4.data = NULL;
存在__Pyx_PyObject_to_MemoryviewSlice_ds_double
。因此,在绑定内存视图时,它确实需要gil。
答案 0 :(得分:1)
你应该使用一个numpy数组,因为你的cdef double [:]声明被Python对象包装,并且它的使用受到限制而没有gil。您可以尝试切片double[:]
def test()
cdef double[:] asd
with nogil:
asd[:1]
您的输出将是:
with nogil:
asd[:1]
^
------------------------------------------------------------
prueba.pyx:16:11: Slicing Python object not allowed without gil
使用numpy数组会编译; numpy使用Python缓冲区protocole,并与Cython顺利集成(Google Summercamp项目的资金来源于此)。所以def中没有出现包装冲突:
import numpy as np
cdef double testA(double[:] x) nogil:
return x[0]
cpdef test():
xx = np.zeros(2, dtype = 'double')
with nogil:
a = testB(xx)
print(a)
这将构建带有test()的模块。但它以一种丑陋的方式崩溃(至少在mi PC上):
Process Python segmentation fault (core dumped)
如果我可以坚持使用我的(现已删除的)上一个答案,根据我自己的经验,在处理Cython内存视图和C数组时,传递指针的工作方式与C中预期的一样。大多数包装都是避免的(实际上,你正在编写完全符合您想要的方向的代码,从而进行不必要的包装。这将按预期编译和运行:
cdef double testB(double* x) nogil:
return x[0]
def test():
cdef double asd[2]
asd[0] = 1
asd[1] = 2
with nogil:
a = testB(asd)
print(a)
并且,在compilig之后:
In [5]: import prueba
In [6]: prueba.test()
1.0
Memoryviews本身不是Python对象,但它们可以包含在一个中。我不是一个熟练的Cython程序员,所以有时我得到意想不到的包装或代码仍然在Python级别,当我认为它将在C.试用和错误让我到指针策略。