Python 是当今使用最流行的编程语言之一,这有充分的理由:它是开源的,它有广泛的用途(例如 Web 编程、商业应用程序、游戏、科学编程等等),并且它有一个充满活力和专注的社区支持它。这个社区是我们拥有如此庞大、多样化的软件包的原因,这些软件包在 Python 包索引 (PyPI) 中可用,以扩展和改进 Python 并解决不可避免出现的故障。
在本系列中,我们将介绍七个可以帮助您解决常见 Python 问题的 PyPI 库。首先是:Cython,一种简化为 Python 编写 C 扩展的语言。
Cython
Python 使用起来很有趣,但有时,用它编写的程序可能很慢。所有运行时动态调度都付出了巨大的代价:有时它比用 C 或 Rust 等系统语言编写的等效代码慢 10 倍。
将代码片段移动到全新的语言可能会在精力和可靠性方面付出巨大的代价:所有这些手动重写工作都不可避免地会引入错误。我们能鱼与熊掌兼得吗?
为了让这个练习有优化的目标,我们需要一些慢的东西。有什么比意外的斐波那契数列指数实现更慢的呢?
def fib(n):
if n < 2:
return 1
return fib(n-1) + fib(n-2)
由于对 fib 的调用会导致两次调用,因此这种非常低效的算法需要很长时间才能执行。例如,在我的新笔记本电脑上,fib(36) 大约需要 4.5 秒。当我们探索 Python 的 Cython 扩展如何提供帮助时,这 4.5 秒将成为我们的基线。
使用 Cython 的正确方法是将其集成到 setup.py 中。但是,使用 pyximport 是一种快速简便的尝试方法。让我们将上面的 fib 代码放入 fib.pyx 中,并使用 Cython 运行它。
>>> import pyximport; pyximport.install()
>>> import fib
>>> fib.fib(36)
仅使用 Cython 而不更改代码就将我的笔记本电脑上算法运行时间缩短到大约 2.5 秒。这几乎减少了 50% 的运行时,而且几乎没有付出任何努力;当然,这是一块可以吃又有的美味蛋糕!
稍加努力,我们可以让事情变得更快。
cpdef int fib(int n):
if n < 2:
return 1
return fib(n - 1) + fib(n - 2)
我们将 fib 中的代码移动到使用 cpdef 定义的函数中,并添加了几个类型注释:它接受一个整数并返回一个整数。
这使得它快得多——大约 0.05 秒。它太快了,以至于我可能会开始怀疑我的测量方法包含噪声:以前,这种噪声在信号中丢失了。
因此,下次您的某些 Python 代码在 CPU 上花费的时间过长,可能会在这个过程中启动一些风扇时,为什么不看看 Cython 是否可以解决问题呢?
在本系列的下一篇文章中,我们将介绍 Black,一个自动更正代码中格式错误的工具。
4 条评论