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

标签 python c cython

所以我在 Python 脚本中有一段时间关键的代码,我决定编写一个 Cython 模块(只有一个功能——我需要的)来替换它。不幸的是,我从 Cython 模块(我在我的 Python 脚本中调用)调用的函数的执行速度几乎没有我在各种其他场景中测试的那么快。请注意,由于契约(Contract)法,我不能共享代码本身!请看以下案例,作为我问题的初步描述:

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

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

(3) 在 Python 脚本中调用 Cython 函数,在我的 Python 脚本的 main 函数中使用 Cython 函数;在全局和局部命名空间中使用 Cython 函数进行测试,速度与案例 (1) 相同。

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

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

“我还没有尝试过的一件事是让这个最内层的循环成为一个函数,然后从那里开始。” 编辑:刚试过这个 - 运气不好。

感谢您提出的任何建议 - 我深感遗憾无法分享我的代码...这有点伤害我的灵魂,但我的客户就是不能让这段代码四处流传。如果我可以提供任何其他信息,请告诉我!

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

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

根本问题:数据类型。我编写了我的 Cython 函数以期待一个充满标准 float 的列表。不幸的是,我的代码是这样做的:

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 函数之前它确实被使用了几次。

最佳答案

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

from module import function

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

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

关于python - 在 Python 脚本中调用 Cython 函数时出现意外的性能损失?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7101956/

相关文章:

python - 如何在 Easygui 中制作多功能输入框?

python - 你如何使用django将类似的帖子添加到详细信息页面

C 程序 - 从 LinkedList 中删除重复项

python - 无法将 cpplist 导入 Cython?

python - cython中def、cdef、cpdef的定义

python - 使用 Cython 为困难的 C 头文件编写 Python 包装器

python - Python 3 中的 For 循环

python - Tkinter:将标准输出重定向到只读文本

c - 将匿名 PIPE HANDLE 传递给子进程

c - 将数值二维数组保存到图像