Python 看到Cython没有加速
我试图用Cython来加速一些数值代码中昂贵的Python for循环,但遇到了一个问题,我几乎看不到任何加速,我想我可能不得不对我的代码进行Cython化,这比我希望的要多得多 举个例子,假设我有以下两个函数,它们已经被cythonized,并且是一个更大类的一部分:Python 看到Cython没有加速,python,python-3.x,cython,cythonize,Python,Python 3.x,Cython,Cythonize,我试图用Cython来加速一些数值代码中昂贵的Python for循环,但遇到了一个问题,我几乎看不到任何加速,我想我可能不得不对我的代码进行Cython化,这比我希望的要多得多 举个例子,假设我有以下两个函数,它们已经被cythonized,并且是一个更大类的一部分: def update(self, double[::1] state_data, double[::1] sensor_data, double sigma): cdef int i cdef int N = s
def update(self, double[::1] state_data, double[::1] sensor_data, double sigma):
cdef int i
cdef int N = state_data.shape[0]
for i in range(N):
self.output[i] = self.process_sensor_data(state_data[i], sensor_data, sigma)
def process_sensor_data(self, double current_state, double[::1] sensor_data, double sigma):
cdef int i
cdef int N = sensor_data.shape[0]
cdef double x
cdef double y
for i in range(N):
x += self.do_something(current_state, sigma)
y += self.do_something_else(sensor_data)
return min(x,y)
如上所述,update()
函数接受一些numpy数组(double[::1]
)和一个浮点数,然后运行一个for循环,调用process\u sensor\u data()
函数。然后,process\u sensor\u data()
函数运行自己的for循环,该循环调用另外两个函数,分别称为do\u something()
和do\u something\u else()
,它们是在类中的其他地方定义的
现在让我们假设我可以将dou_something()
函数完全循环化,从而可以将其定义为一个带有函数头的fastcdef
函数
cdef double do_something(self, double current_state, double sigma):
...
但是我无法对
do\u something\u else()
函数进行循环化(例如,它可能会调用numpy或scipy库中的某些函数)。这是否意味着过程中的for循环_sensor_data()
和更新()
仍将以与vanilla Python for循环类似的速度运行,而Cython不会有太大的加速
换句话说,如果我像上面那样对for循环进行cythonize,但是for循环中有一些函数调用和/或计算无法进行cythonized(即,如果Cython的html注释输出在for循环中显示一些黄色代码行),这是否意味着我在使用Cython时不会看到太多的加速
从我自己的实验来看,不幸的是似乎是这样,但我想确保我没有发疯。在我的代码中,有一个函数在Python中执行大约需要20秒,但在我尝试将慢速for循环循环循环化之后,仍然需要大约20秒来执行。我花了好几个小时,在兔子洞里尝试尽可能多地在调用循环中调用变量和函数,我开始认为在C++中实现类更简单,更易读。任何帮助或指导都将不胜感激,谢谢。Cython并不总是更快,特别是如果您继续使用Python数据类型而不是C数据类型。另外,请注意,Python和C数据类型之间的转换可以在Cython中隐式进行,而且代价可能很高
你也可以看看numba的Nopyton decorator和pypy3。“这是否意味着进程中的for循环\u sensor\u data()和update()仍将以与vanilla Python for循环类似的速度运行,而Cython没有太多的加速?”-这取决于你的意思,但它们是外部循环,因此,对它们进行循环化比CythoNosion内环要重要得多。在C++中实现这一点不太可能产生更好的加速,除非你可以用C++来处理不能进行循环编程的NUMPY/SISPY函数。即使如此,如果NumPy/SciPy功能已经用C编写,可能也没有多大帮助。通常在这种情况下,跨绑定是昂贵的,如果您需要调用NumPy,并且为此必须将本机数据转换为python对象,您将面临一些开销,如果你可以调用C版本的numpy,那么它会更快,但我不知道这是否可能。看看这里,似乎可以从cython调用numpy,而不需要过多的对象转换hanks@geckos,该页面提供了使用类型化MemoryView处理numpy数组并仍然能够快速编写cython代码的好例子,但不幸的是,它似乎没有提到使用numpy函数并仍然能够快速编写cython代码(在循环示例中,他们必须重新编写
np.clip()
),这对于非类函数来说是非常好的,但是尝试jit
Python类是一个非常头疼的问题,并且会降低代码的可读性。我也尝试过pypy3,但它似乎不适用于我经常使用的一些python库(例如,rospy
)。在尝试使用numba和Py3并失败之后,cython感觉自己是试图用Python编写快速数值/科学计算代码的“最后希望”。然而,在看到cythonized循环速度没有得到提高(如果它们中有numpy和scipy函数调用)之后,快速Python代码似乎是不可能的:(您是否尝试了探查器?可能热点在某个不明显的地方?是的,95%的处理时间发生在已识别的单个函数中。