在Python脚本中调用Cython函数时意外的性能损失?

时间:2011-08-18 03:11:17

标签: python c cython

所以我在Python脚本中有一个时间要求严格的代码部分,我决定编写一个Cython模块(带有一个函数 - 我只需要它)来替换它。不幸的是,我从Cython模块(我在Python脚本中调用)调用的函数的执行速度并不像我在各种其他场景中测试它那么快。请注意,由于合同法,我无法共享代码!请参阅以下案例,并将其作为我的问题的初始描述:

(1)使用Python解释器导入模块并运行该函数,执行Cython函数。运行相对较快(约100次单独测试约0.04秒,而原始约0.24秒)。

(2)在'global'级别的Python脚本中调用Cython函数(即不在任何函数内)。与案例(1)的速度相同。

(3)在Python脚本中调用Cython函数,在Python脚本的主函数中使用Cython函数;在全局和本地命名空间中使用Cython函数进行测试,所有这些都与case(1)具有相同的速度。

(4)与(3)相同,但在所述Python函数中的简单for循环中。与案例(1)的速度相同。

(5)问题!与(4)相同,但在另一个for循环中:Cython函数的执行时间(无论是全局调用还是本地调整)是其他情况的~10倍,这是我需要调用函数的地方。报告这个循环没什么奇怪的,我测试了这个循环的所有组件(调整/删除我能做的)。我也尝试使用'while'循环来玩咯咯,但无济于事。

“我还有一件事要做的就是让这个最里面的循环成为一个功能并从那里开始。” 编辑:试过这个 - 没有运气。

感谢您提出的任何建议 - 我深感遗憾无法分享我的代码......它会让我的灵魂受到一点伤害,但我的客户却无法让这些代码浮出水面。如果我能提供任何其他信息,请告诉我们!

- 真实问题和初始(丑陋)解决方案 -

事实证明,这种情况下最好的提示是显而易见的(像往常一样):它不是导致问题的for循环;为什么会这样?经过几次测试之后,很明显我调用我的Cython函数的方式是错误的,因为我可以在别处调用它(使用不同于'真正的'Cython函数的输入变量)而没有性能损失问题。

潜在问题:数据类型。我写了我的Cython函数,期待一个充满标准浮点数的列表。不幸的是,我的代码做到了这一点:

function_input = list(numpy_array_containing_npfloat64_data) # yuck.
type(function_input[0]) = numpy.float64
output = Cython_Function(function_input)

在Cython函数中:

def Cython_Function(list function_input):
    cdef many_vars
    """process lots of vars expecting C floats""" # Slowness from converting numpy.float64's --> floats???
    type(output) = list
    return output

我知道我可以在Cython函数中更多地使用类型,我很可能会这样做以防止必须“列出”现有的numpy数组。无论如何,这是我目前的解决方案:

function_input = [float(x) for x in function_input]

我欢迎任何反馈和改进建议。 function_input numpy数组实际上并不需要numpy.float64的精度,但在传递给我的Cython函数之前它会被使用几次。

2 个答案:

答案 0 :(得分:2)

可能是,虽然单独使用Cython实现的每个函数调用都比其相应的Python函数更快,但是在Cython函数调用中有更多的开销,因为它必须在模块命名空间中查找名称。您可以尝试首先将函数分配给本地可调用函数,例如:

from module import function

def main():
    my_func = functon
    for i in sequence:
        my_func()

如果可能的话,你应该尝试在Cython函数中包含循环,这会将Python循环的开销减少到编译的C循环的(非常小的)开销。我知道这可能是不可能的(即需要来自全球/更大范围的参考),但值得您进行一些调查。祝好运!

答案 1 :(得分:1)

function_input = list(numpy_array_containing_npfloat64_data)

def Cython_Function(list function_input):
    cdef many_vars

我认为问题在于使用numpy数组作为列表...你不能使用np.ndarray作为Cython函数的输入吗?

def Cython_Function(np.ndarray[dtype=np.float64] input):
   ....