Python 是当今使用最流行的编程语言之一,这有很多充分的理由:它是开源的,用途广泛(例如 Web 编程、商业应用程序、游戏、科学编程等等),并且拥有充满活力和专注的社区为其提供支持。正是这个社区使我们在 Python 包索引 (PyPI) 中拥有如此庞大而多样化的软件包,以扩展和改进 Python 并解决不可避免出现的故障。
在本系列文章中,我们将介绍七个 PyPI 库,它们可以帮助您解决常见的 Python 问题。首先: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 条评论