考虑这个虚拟的Cython代码:
#!python
#cython: boundscheck=False
#cython: wraparound=False
#cython: initializedcheck=False
#cython: cdivision=True
#cython: nonecheck=False
import numpy as np
# iterator function
cdef double[:] f(double[:] data):
data[0] *= 1.01
data[1] *= 1.02
return data
# looping function
cdef double[:] _call_me(int bignumber, double[:] data):
cdef int ii
for ii in range(bignumber):
data = f(data)
return data
# helper function to allow calls from Python
def call_me(bignumber):
cdef double[:] data = np.ones(2)
return _call_me(bignumber, data)
现在,如果我对此进行 cython -a ,它会以黄色显示返回语句 . 我在一个性能非常关键的程序中做了类似的事情,根据分析,这实际上减慢了我的代码速度 . 那么,为什么cython需要python用于这些返回语句?带注释的文件提供了一个提示:
PyErr_SetString(PyExc_TypeError,"Memoryview return value is not initialized");
令人惊讶的是,谷歌搜索 cython "Memoryview return value is not initialized" 给出的结果为零 .
1 回答
缓慢的部分不是你想象的那样 . 缓慢的部分是(嗯...主要)
不是
f(data)
.data =
.这将指定一个
struct
,其定义如下并且提到的任务确实如此
其中
__pyx_t_3
属于该类型 . 如果这在循环中大量完成,复制结构比执行函数的普通主体需要更长的时间 . 我在纯C中做了一个计时,它给出了相似的数字 .(编辑注释:分配实际上主要是一个问题,因为它还会导致结构和其他副本的生成不被优化 . )
However ,整件事看起来很傻 . 复制结构的唯一原因是,如果某些内容发生了变化,但没有任何变化 . 记忆指向同一个地方,数据指向同一个地方,形状,步幅和偏移是相同的 .
我看到避免
struct
副本的唯一方法是不更改它引用的任何内容(也就是说 . 总是返回给定的memoryview
) . 如果你打破了某些东西,那就哭了 .另请注意,您可以将函数设置为
nogil
,因此它与回溯到Python无关 .EDIT
C的优化编译器让我略微偏离 . 基本上,我删除了一些分配,并删除了其他东西 . 基本上慢速路径是这样的:
(没有优化编译) . 我不是C程序员,所以如果我所做的事情在某种程度上与我复制计算机生成的代码的事实没有直接联系,那么道歉 .
我知道这没有用,但我尽了最大努力,好吗?