如何避免 PyObject_to_MemoryviewSlice, GOTREF / DECREF Python API 调用?
How to avoid PyObject_to_MemoryviewSlice, GOTREF / DECREF Python API calls?
我在对我的代码进行 cythonizing 时遇到问题,更具体地说是以下(和类似的)片段:
cdef double [:,:] grad_d_him_d_jm
grad_d_ihm_d_jm = grad_d_im_d_jm(...)
其中 grad_d_im_d_jm(...) 会 return 双 [:,:] 内存视图。
此代码将由 Cython 翻译成以下 C 代码:
__pyx_t_1 = __pyx_f_24gradient_better_c_mviews_grad_d_im_d_jm(__pyx_v_i, __pyx_v_j, __pyx_v_m, __pyx_v_structure, __pyx_v_distances);
if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 203; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_7 = __Pyx_PyObject_to_MemoryviewSlice_dsds_double(__pyx_t_1);
if (unlikely(!__pyx_t_7.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 203; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_grad_d_ihm_d_jm = __pyx_t_7;
__pyx_t_7.memview = NULL;
__pyx_t_7.data = NULL;
当我在循环中执行此操作时,我怀疑 Python API 调用对我的代码速度有相当大的影响。
GOTREF / DECREF 调用也发生在其他情况下,以及 PyFloat_asFloat:
cdef float sp
sp = scalar_product()
其中 scalar_product() return 是一个 cdef 浮点数。此代码段被翻译成
__pyx_t_1 = __pyx_f_24gradient_better_c_mviews_scalar_product(__pyx_v_i, __pyx_v_j, __pyx_v_m, __pyx_v_structure);
if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_2 = __pyx_PyFloat_AsFloat(__pyx_t_1);
if (unlikely((__pyx_t_2 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_sp = __pyx_t_2;
我是 运行 Python 2.7.11+ 和 Cython 0.23.4。如果您能告诉我 a) 这与性能无关或 b) 如何修复它,我将不胜感激。
如果我可以改进问题,请告诉我,我很乐意这样做。
这些似乎是 Cython 引用计数的一部分 API 已解释 here。
我的猜测是 grad_d_im_d_jm
return 是一个 Python 对象(例如 NumPy 数组),因此 Cython 必须在获得内存视图后递减对象引用计数器。
至于 scalar_product
,我认为它要么是 def(而不是 cdef),要么是无类型的。例如下面的
cdef g():
return 1.0
编译为
// ...
__Pyx_XDECREF(__pyx_r);
__Pyx_INCREF(__pyx_float_1_0);
__pyx_r = __pyx_float_1_0;
goto __pyx_L0;
但是,一旦您指定 return 类型,重新计数调用就消失了
cdef float g():
return 1.0
变成
// ...
__pyx_r = 1.0;
goto __pyx_L0;
我在对我的代码进行 cythonizing 时遇到问题,更具体地说是以下(和类似的)片段:
cdef double [:,:] grad_d_him_d_jm
grad_d_ihm_d_jm = grad_d_im_d_jm(...)
其中 grad_d_im_d_jm(...) 会 return 双 [:,:] 内存视图。 此代码将由 Cython 翻译成以下 C 代码:
__pyx_t_1 = __pyx_f_24gradient_better_c_mviews_grad_d_im_d_jm(__pyx_v_i, __pyx_v_j, __pyx_v_m, __pyx_v_structure, __pyx_v_distances);
if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 203; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_7 = __Pyx_PyObject_to_MemoryviewSlice_dsds_double(__pyx_t_1);
if (unlikely(!__pyx_t_7.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 203; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_grad_d_ihm_d_jm = __pyx_t_7;
__pyx_t_7.memview = NULL;
__pyx_t_7.data = NULL;
当我在循环中执行此操作时,我怀疑 Python API 调用对我的代码速度有相当大的影响。
GOTREF / DECREF 调用也发生在其他情况下,以及 PyFloat_asFloat:
cdef float sp
sp = scalar_product()
其中 scalar_product() return 是一个 cdef 浮点数。此代码段被翻译成
__pyx_t_1 = __pyx_f_24gradient_better_c_mviews_scalar_product(__pyx_v_i, __pyx_v_j, __pyx_v_m, __pyx_v_structure);
if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_2 = __pyx_PyFloat_AsFloat(__pyx_t_1);
if (unlikely((__pyx_t_2 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_sp = __pyx_t_2;
我是 运行 Python 2.7.11+ 和 Cython 0.23.4。如果您能告诉我 a) 这与性能无关或 b) 如何修复它,我将不胜感激。 如果我可以改进问题,请告诉我,我很乐意这样做。
这些似乎是 Cython 引用计数的一部分 API 已解释 here。
我的猜测是 grad_d_im_d_jm
return 是一个 Python 对象(例如 NumPy 数组),因此 Cython 必须在获得内存视图后递减对象引用计数器。
至于 scalar_product
,我认为它要么是 def(而不是 cdef),要么是无类型的。例如下面的
cdef g():
return 1.0
编译为
// ...
__Pyx_XDECREF(__pyx_r);
__Pyx_INCREF(__pyx_float_1_0);
__pyx_r = __pyx_float_1_0;
goto __pyx_L0;
但是,一旦您指定 return 类型,重新计数调用就消失了
cdef float g():
return 1.0
变成
// ...
__pyx_r = 1.0;
goto __pyx_L0;