8个核心编码技巧,可实现更快的python运行速度

原文来自外文:翻译

前言

总的来说,人们使用python是因为它方便且易于编程,而不是因为它很快。大量的第三方库和对Python的工业支持的广泛性弥补了它没有Java或C的原始性能。开发速度优先于执行速度。

但在许多情况下,它不必是一个非此即彼的命题。适当地优化,Python应用程序可以以惊人的速度运行——也许不是Java或C快,但对于Web应用程序、数据分析、管理和自动化工具以及其他大多数目的来说都足够快。实际上,您可能会忘记您是在用应用程序性能来换取开发人员的生产力。

优化python性能并不能归结为任何一个因素。相反,它是关于应用所有可用的最佳实践,并选择最适合当前场景的最佳实践。(Dropbox中的人们有一个关于Python优化功能最引人注目的例子。)

在这篇文章中,我将概述许多常见的Python优化。其中一些是只需将一个项目切换到另一个项目(如更改python解释器)即可实现的嵌入式度量,但实现最大回报的项目将需要更详细的工作。

8个核心编码技巧,可实现更快的python运行速度

1。Memoize(缓存)重复使用的数据

当你能做到一次并保存结果时,千万不要做一千次工作。如果有一个经常调用的函数返回可预测的结果,那么python为您提供了将结果缓存到内存中的选项。返回相同结果的后续调用几乎会立即返回。

各种各样的例子展示了如何做到这一点;我最喜欢的记忆几乎是最少的。python的一个本机库functools具有@functools.lru缓存装饰器,它缓存最近对函数的n个调用。当正在缓存的值发生变化,但在特定的时间窗口内是相对静态的时,这很方便。一天中最新使用的项目列表就是一个很好的例子。

2。将数学移动到numpy

如果您正在进行基于矩阵或数组的数学运算,并且不希望Python解释器妨碍您的工作,请使用numpy。通过利用C库进行繁重的工作,numpy提供了比本机python更快的数组处理。它还比Python的内置数据结构更有效地存储数字数据。

相对来说,非异类的数学也可以被numpy大大加快。该包为许多常见的python数学操作(如min和max)提供了替换,这些操作的速度比原来的python快很多倍。

numpy的另一个好处是更有效地使用大型对象的内存,比如拥有数百万个项目的列表。一般来说,像numpy中那样的大型对象如果用传统的python来表示,则占用大约四分之一的内存。请注意,它有助于从作业的正确数据结构开始,即优化本身。

重写python算法以使用numpy需要一些工作,因为数组对象需要使用numpy的语法声明。但是numpy在实际的数学运算中使用了python现有的习语(+、-,等等),所以从长远来看,切换到numpy并不会太令人迷惑。

3。使用C库

numpy使用C语言编写的库是一种很好的模拟策略。如果有一个现有的C库可以满足您的需要,那么Python及其生态系统提供了几个选项来连接到该库并利用其速度。

最常见的方法是使用Python的CTypes库。因为ctypes与其他python应用程序(和运行时)广泛兼容,所以它是最佳的开始位置,但它远不是镇上唯一的游戏。cffi项目为c.cython提供了一个更优雅的接口(见下文),也可以用来包装外部库,尽管代价是必须学习cython的标记。

8个核心编码技巧,可实现更快的python运行速度

学习从来不是一个人的事情,要有个相互监督的伙伴,工作需要学习python或者有兴趣学习python的伙伴可以私信回复小编“学习” 获取资料,一起学习

4。与多处理并行

传统的python应用程序——那些在cpython中实现的应用程序——一次只执行一个线程,以避免在使用多个线程时出现状态问题。这是臭名昭著的全球口译员锁(gil)。它的存在有充分的理由,这并没有使它变得更加华丽。

随着时间的推移,gil的效率显著提高(运行python 3而不是python 2的另一个原因),但核心问题仍然存在。一个cpython应用程序可以是多线程的,但是cpython不允许这些线程在多个核心上并行运行。

为了解决这个问题,python提供了多处理模块来在不同的核心上运行python解释器的多个实例。状态可以通过共享内存或服务器进程来共享,数据可以通过队列或管道在进程实例之间传递。

您仍然需要在进程之间手动管理状态。另外,在启动多个Python实例并在其中传递对象的过程中,不会有太多的开销。但是对于长期运行的进程来说,多处理库是非常有用的,因为它可以从跨核心的并行性中获益。

另外,使用C库的python模块和包(如numpy)完全避免使用gil。这也是他们被推荐提速的另一个原因。

5。知道你的库在做什么

简单地输入XYZ并利用无数其他程序员的工作是多么方便!但是您需要知道,第三方库可以改变应用程序的性能,而不是总是为了更好。

有时,这以明显的方式表现出来,例如当来自特定库的模块构成瓶颈时。(再次强调,剖析会有所帮助。)有时情况不那么明显。示例:Pyglet是一个用于创建窗口化图形应用程序的简便库,它自动启用调试模式,这会显著影响性能,直到显式禁用它为止。除非您阅读文档,否则您可能永远不会意识到这一点。阅读并被告知。

6。注意平台

python运行跨平台,但这并不意味着每个操作系统(windows、linux、os x)的特性都是在python下抽象出来的。大多数时候,这意味着要了解平台的具体情况,比如路径命名约定,对于这些约定,有助手函数。

但在性能方面,了解平台差异也很重要。例如,在Windows上,需要计时器精度小于15毫秒(例如,对于多媒体)的python脚本将需要使用Windows API调用来访问高分辨率计时器或提高计时器分辨率。

7。与PyPy同行

cpython是Python最常用的实现,它将兼容性优先于原始速度。对于那些想把速度放在首位的程序员来说,有pypy,一个配备了jit编译器的python实现来加速代码执行。

因为pypy是作为cpython的替代品而设计的,所以它是快速提高性能的最简单方法之一。许多常见的python应用程序将在pypy上运行。一般来说,应用程序越依赖于“普通”的python,就越有可能在pypy上运行而不进行修改。

然而,充分利用PYPY可能需要测试和研究。您会发现长时间运行的应用程序从Pypy获得最大的性能收益,因为编译器会分析一段时间后的执行情况。对于运行和退出的短脚本,您最好使用cpython,因为性能提升不足以克服JIT的开销。

请注意,pypy对python 3的支持仍然落后于几个版本;它目前支持python 3.2.5。使用最新的python特性(如async和await-co例程)的代码将无法工作。最后,使用ctypes的python应用程序的行为可能并不总是如预期的那样。如果您正在编写可能同时在pypy和cpython上运行的东西,那么为每个解释器分别处理用例可能是有意义的。

其他通过抖动加速python的实验仍在取得成果。其中包括一个微软项目pyjion,它为cpython提供了一个JIT接口。微软提供了自己的JIT作为概念证明。

8个核心编码技巧,可实现更快的python运行速度

8。升级至python 3

如果您使用的是python 2.x,并且没有覆盖的原因(比如不兼容的模块)来坚持使用它,那么您应该跳到python 3。

除了python 3作为语言的未来,python 3中还提供了许多构造和优化,而python 2.x中没有这些构造和优化。例如,python 3.5通过将async和wait关键字作为语言语法的一部分来减少异步编程的麻烦。python 3.2对全局解释器锁进行了重大升级,显著改进了python处理多个线程的方式。

相关推荐