Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发。
很多讨厌 Python 的人总是说,他们不想用 Python 的原因之一是它很慢。嗯,特定程序(无论使用哪种编程语言)的快与慢,很大程度上取决于编写该程序的开发人员及其编写高效程序并优化的能力。
因此,我们来证明一些人错误的观点,并看看如何改善 Python 程序的性能使其真正运行的很快。
计时与分析
在开始优化之前,我们首先需要找出代码中的哪些部分实际上会导致整个程序变慢。有时候程序的瓶颈可能很明显,但是如果还是不知道它在哪里,这里可以提供一些参考:
注意:这是我用于演示的程序,将计算 e 的 x 次幂(取自 Python 文档):

最笨的分析方式
首先,最简单且最直观的方式是使用 Unix time 命令:

如果只是想对整个程序计时,这应该会有效,但是这还不够。
最详细的分析方式
相对地另一个极端方式是使用 cProfile,它可以展示非常多的信息:

这里,我们使用了 cProfile 模块以及 time 参数来运行脚本,以便按照内部时间(cumtime)进行按行排序。这里提供了很多信息,上面看到的大概只有实际输出内容的 10%。从中可以看到 exp 函数是耗时的罪魁祸首(惊讶吧),现在来详细地了解一下时序与性能分析。
对特定功能计时
现在我们已经知道要关注哪里了,我们可能想要对慢方法进行计时,而不关系其他代码。为此,我们可以使用简单的装饰器:

然后可以将这个装饰器用于待测试的方法,如下所示:

输出结果如下:

这里要考虑的是我们实际(想要)测量的时间。Time 包中提供了 time.perf_counter 和 time.process_time 函数。这里的区别在于 time.perf_counter 返回的是绝对值,其中包括 Python 程序进程未运行的时间,因此它可能会受到计算机负载的影响。而 process_time 只返回用户时间(不包括系统时间),这就是进程运行的时间。
让程序更快
现在,这部分就有趣了。我们来让你的 Python 程序运行的更快。我(基本上)不会向你展示那些可以解决性能问题的银弹,技巧和代码段。这里更多地是常见的思考和策略,这些思考和策略使用时可能会对性能产生巨大影响。甚至某些情况下,可以将速度提高 30%。
使用内置数据类型
这个很显然,内置数据类型非常快,尤其是与我们自定义的类型(例如树或者链表)相比。这主要是因为内置的数据类型是由 C 实现的,而在 Python 中写的代码运行速度实在无法与之相比。
使用 lru_cache 缓存或持久化
我已经在之前的博客中展示过这部分内容,但我觉得还是有必要再通过一个简单的例子重现一下:

上面的函数使用 time.sleep 模拟大量计算耗时。第一次调用参数为 1,然后等待 2 秒钟才返回结果。再次调用时,已经缓存了结果,所以可以跳过函数体直接返回结果。
使用本地变量
程序运行速度与在每个作用域中查找变量有关。我在每个作用域中都会写代码,这里不仅会用到本地变量,还有全局变量。实际上,访问不同作用域的变量速度也是不同的,比如在函数内访问本地变量(最快),访问类层面变量(如 self.name,比较慢),以及全局变量,比如例子中导入的函数 time.time (这种最慢)。
你可以通过这些看似不必要(或者干脆无用)的部分来提高性能,像下面这样:

使用函数
这里看起来可能不太直观,因为函数调用会将很多东西都放到了堆栈中,并且由函数返回时创建开销。这与前一点有些关联。如果你只是将你的代码放到一个文件中,而不是将其放入函数,由于是访问全局变量,其速度将会大大降低。因此,你可以通过将整个代码包装在 main 函数中并调用一次来实现加速。如下所示:

不要访问属性
另外一个可能会让程序变慢的问题是运算符 . ,它是在访问对象属性时使用的。这个运算符使用 __getattribute__,这会触发字典查找,在代码中产生额外的开销。那么,我们怎样才能真正避免(禁止)始终这种方式呢?

谨慎使用字符串
当需要循环使用模板(%s)或者 .format() 运行时,字符串操作可能会变得非常慢。我们有什么更好的办法吗?据Raymond Hettinger 的推文描述,最应该使用的是 f-string,这是一个最易读、简洁且最快的办法。所以,据推文中描述的,下面列出了最快到最慢的一些方法:

使用生成器也非常快
使用生成器本身并不快,而是生成器允许进行延迟计算,从而节省了内存,但不是直接节省了时间。不过,节约使用内存也可能使应用程序实际运行得更快。它是怎么做到的呢?其实,如果你有大量的数据集,并且你没有使用生成器(迭代器),那么这些数据可能会溢出 CPU 的一级缓存。这会降低在内存中访问的效率。
在性能方面,CPU 会尽可能快地保存其正在缓存中的数据。这一点非常重要。你可以看一下Raymond Hettingers 的访谈,其中提到了这个问题。
总结
性能优化的第一条规则是不要做优化。但是如果必须要做的话,我希望这些提示可以对你提供些帮助。英文原文:https://martinheinz.dev/blog/13
译者:居老师的龙尾巴
Python性能优化:揭示慢速真相并提升速度
本文探讨了如何反驳关于Python速度慢的误解,通过计时分析找出程序瓶颈,介绍使用内置数据类型、lru_cache缓存、本地变量优化、函数封装等策略,提升Python程序的性能,给出速度优化的实际案例和建议。
1671

被折叠的 条评论
为什么被折叠?



