Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/322.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何避免PyObject到MemoryviewSlice、GOTREF/DECREF Python API调用?_Python_Cython_Memoryview - Fatal编程技术网

如何避免PyObject到MemoryviewSlice、GOTREF/DECREF Python API调用?

如何避免PyObject到MemoryviewSlice、GOTREF/DECREF Python API调用?,python,cython,memoryview,Python,Cython,Memoryview,我对代码进行cythonization有一个问题,更具体地说是以下(和类似的)sniplets: cdef double [:,:] grad_d_him_d_jm grad_d_ihm_d_jm = grad_d_im_d_jm(...) grad_d_im_d_jm(…)将返回一个双[:,:]内存视图。 此代码将由Cython翻译为以下C代码: __pyx_t_1 = __pyx_f_24gradient_better_c_mviews_grad_d_im_d_jm(__pyx_v_i,

我对代码进行cythonization有一个问题,更具体地说是以下(和类似的)sniplets:

cdef double [:,:] grad_d_him_d_jm
grad_d_ihm_d_jm = grad_d_im_d_jm(...)
grad_d_im_d_jm(…)将返回一个双[:,:]内存视图。 此代码将由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;
当我在循环中执行此操作时,我怀疑pythonapi调用对我的代码速度有相当大的影响

GOTREF/DECREF调用也会在其他情况下发生,以及PyFloat_asFloat:

cdef float sp
sp = scalar_product()
其中,scalar_product()返回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的一部分

我的猜测是,
grad_d_im_d_jm
返回一个Python对象(例如NumPy数组),因此Cython必须在获得memoryview后减少对象引用计数器

至于标量产品,我认为它要么是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;
但是,一旦指定了返回类型,refcounting调用就消失了

cdef float g():
    return 1.0
变成

// ...
__pyx_r = 1.0;
goto __pyx_L0;

这些似乎是Cython引用计数API的一部分

我的猜测是,
grad_d_im_d_jm
返回一个Python对象(例如NumPy数组),因此Cython必须在获得memoryview后减少对象引用计数器

至于标量产品,我认为它要么是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;
但是,一旦指定了返回类型,refcounting调用就消失了

cdef float g():
    return 1.0
变成

// ...
__pyx_r = 1.0;
goto __pyx_L0;

谢谢你的回答!scalar_乘积是cdef,其返回值是cdef浮点数。grad_d_im_d_jm也是如此;只有返回的值是cdef的浮点型2D memoryview。事实上,当打印类型(grad_d_im_d_jm)时,它会说它是一个memoryviewslice。我在grad_d_im_d_jm()中所做的是用mv=numpy.zero((n,n))初始化memoryview,然后向单个元素添加内容。我查看了refnanny,但还没有找到关闭它的方法(只是作为runtests.py的一个选项)。你知道吗?保姆只是用来调试Cython本身的。例如,生成的C文件有一个ifdef,用
Py\u DECREF
替换
Py\u DECREF
,除非用户特别设置
-DCYTHON\u REFNANY
。是否可以共享相关代码?我不能用存根函数在本地重现这个问题。我觉得是时候让我感到尴尬了。到目前为止,我主要将单个函数循环化为(cp)defs,但在我的代码中,我调用了许多cdef'ed函数。实际上我没有想到在函数头中指定返回类型!我没有仔细阅读你的答案,否则我会马上注意到的。非常抱歉!不过,有趣的是,指定返回类型只会导致大约15%的加速。无论如何,非常感谢!你的答案当然是正确的-我只是认为我已经在函数体中用cdef’ing返回变量指定了返回类型。谢谢你的回答!scalar_乘积是cdef,其返回值是cdef浮点数。grad_d_im_d_jm也是如此;只有返回的值是cdef的浮点型2D memoryview。事实上,当打印类型(grad_d_im_d_jm)时,它会说它是一个memoryviewslice。我在grad_d_im_d_jm()中所做的是用mv=numpy.zero((n,n))初始化memoryview,然后向单个元素添加内容。我查看了refnanny,但还没有找到关闭它的方法(只是作为runtests.py的一个选项)。你知道吗?保姆只是用来调试Cython本身的。例如,生成的C文件有一个ifdef,用
Py\u DECREF
替换
Py\u DECREF
,除非用户特别设置
-DCYTHON\u REFNANY
。是否可以共享相关代码?我不能用存根函数在本地重现这个问题。我觉得是时候让我感到尴尬了。到目前为止,我主要将单个函数循环化为(cp)defs,但在我的代码中,我调用了许多cdef'ed函数。实际上我没有想到在函数头中指定返回类型!我没有仔细阅读你的答案,否则我会马上注意到的。非常抱歉!不过,有趣的是,指定返回类型只会导致大约15%的加速。无论如何,非常感谢!你的答案当然是正确的——我只是认为我在函数体中用cdef’ing返回变量指定了返回类型。