我有一个简单的Cython函数,该函数获取memoryview的长度:
cdef int get_length(int[:] a):
return len(a)
我正在使用annotate=True
指令编译代码,以便让我了解Cython在哪里与Python有交互作用。
生成的html在return len(a)
行中包含以下文本:
__pyx_t_1 = __Pyx_MemoryView_Len(__pyx_v_a);
__pyx_r = __pyx_t_1;
goto __pyx_L0;
这种Python交互应该很慢。我有办法防止Python交互吗?我已经尝试过a.shape[0]
,但这没有帮助。
答案 0 :(得分:2)
您不必担心,__Pyx_MemoryView_Len
会变得如此快,因为it is defined如下:
typedef struct {
struct {{memview_struct_name}} *memview;
char *data;
Py_ssize_t shape[{{max_dims}}];
...
} {{memviewslice_name}};
// used for "len(memviewslice)"
#define __Pyx_MemoryView_Len(m) (m.shape[0])
该行的颜色不是黄色,而是淡黄色-这主要意味着它不会产生纯C代码,而是使用了一些_Pyx_XXX
功能,这通常对性能没有不良影响完全没有。
没有Python交互作用-经过C预处理程序传递后,C编译器将看到它,就好像您已经写过:
return a.shape[0]
这会导致白线。
如果您也对多维内存视图的大小感兴趣,那么this SO-question可能值得一读。
注释以黄线显示函数的定义。但是,只有模块加载时的成本(并且一次支付,而不是每次调用函数都支付)才是“黄色”颜色。
看看生成的C代码:
static int __pyx_f_9my_module_get_length(__Pyx_memviewslice __pyx_v_a) {
int __pyx_r;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("get_length", 0);
/* "my_module.pyx":5
*
* cdef int get_length(int[:] a):
* return a.shape[0] # <<<<<<<<<<<<<<
*/
__pyx_r = (__pyx_v_a.shape[0]);
goto __pyx_L0;
/* "my_module.pyx":4
* return 3. * a
*
* cdef int get_length(int[:] a): # <<<<<<<<<<<<<<
* return a.shape[0]
*/
/* function exit code */
__pyx_L0:;
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
RefNannyXXXX
仅在使用CYTHON_REFNANNY
-defined.构建时有效
annotate
工具还显示了另一个代码,它对应于cdef int get_length(int[:] a):
:
/* … */
__pyx_t_1 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_1);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
但是,此代码是__pyx_pymod_exec_XXXXX
/ PyInit_XXXXX
的一部分,并且在加载模块时仅被调用一次。实际上,我不确定这与get_length
有何关系以及为什么需要这样做,但是由于成本如此之小,所以我从来没有足够地去寻找答案。