类似于Cython Memoryview as return value,但除了破解生成的C代码外,我没有看到其他解决方案.
我使用的是Cython3.0,但结果看起来和<3
一样.
下面是一个例子:
# cython: language_level=3, boundscheck=False, cdivision=True, wraparound=False, initializedcheck=False, nonecheck=False
cimport cython
from cython cimport floating
import numpy as np
cimport numpy as np
np.import_array()
def test_func():
cdef np.ndarray[float, ndim=2] arr = np.zeros((5, 5), dtype=np.float32)
cdef float[:, ::1] arr_view = arr
_run(arr_view)
cdef void _run(floating[:, ::1] arr_view) noexcept nogil:
cdef floating[:, :] tmp = _get_upper_left_corner(arr_view)
cdef inline floating[:, :] _get_upper_left_corner(floating[:, ::1] arr) noexcept nogil:
return arr[:-1, :-1]
然后运行cython -a cython_test.pyx
,它显示_get_upper_left_corner
函数有包括GIL获取的Memory view初始化代码,_run
函数有错误判断,因为_get_upper_left_corner
函数可能返回错误(至少我是这么猜的):
+17: cdef inline floating[:, :] _get_upper_left_corner(floating[:, ::1] arr) noexcept nogil:
static CYTHON_INLINE __Pyx_memviewslice __pyx_fuse_0__pyx_f_11cython_test__get_upper_left_corner(__Pyx_memviewslice __pyx_v_arr) {
__Pyx_memviewslice __pyx_r = { 0, 0, { 0 }, { 0 }, { 0 } };
/* … */
/* function exit code */
__pyx_L1_error:;
#ifdef WITH_THREAD
__pyx_gilstate_save = __Pyx_PyGILState_Ensure();
#endif
__PYX_XCLEAR_MEMVIEW(&__pyx_t_1, 1);
__pyx_r.data = NULL;
__pyx_r.memview = NULL;
__Pyx_AddTraceback("cython_test._get_upper_left_corner", __pyx_clineno, __pyx_lineno, __pyx_filename);
goto __pyx_L2;
__pyx_L0:;
if (unlikely(!__pyx_r.memview)) {
#ifdef WITH_THREAD
PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
#endif
PyErr_SetString(PyExc_TypeError, "Memoryview return value is not initialized");
#ifdef WITH_THREAD
__Pyx_PyGILState_Release(__pyx_gilstate_save);
#endif
}
#ifdef WITH_THREAD
__Pyx_PyGILState_Release(__pyx_gilstate_save);
#endif
__pyx_L2:;
return __pyx_r;
}
我本以为内存视图上的切片会创建一个新的 struct .如果有必要,我可以接受 struct 被初始化,但我真的不希望获得GIL.有没有办法在没有GIL的情况下实现返回的记忆观看?如果我需要初始化一些东西,我如何才能在不复制可能很大的Numpy数组的情况下做到这一点(我只是在读取它).
Edit:我把这个例子做得更小了:
# cython: language_level=3, boundscheck=False, cdivision=True, wraparound=False, initializedcheck=False, nonecheck=False
cdef float[:] get_upper_left_corner(float[:] arr) noexcept nogil:
return arr[:2]