编程语言
首页 > 编程语言> > 加快Python程序速度的11个技巧

加快Python程序速度的11个技巧

作者:互联网

总的来说,人们使用Python是因为它方便且对程序员友好,而不是因为它很快。大量的第三方库和对Python的行业支持广度弥补了它不具有Java或C的原始性能的严重不足。开发速度优先于执行速度。

但是在很多情况下,它不一定是一个或一个或一个命题。经过适当优化的Python应用程序可以以惊人的速度运行-也许不是Java或C的运行速度快,但足以用于Web应用程序,数据分析,管理和自动化工具以及大多数其他目的。您实际上可能会忘记,为了提高开发人员的生产力而牺牲了应用程序性能。

优化Python性能并不能归结为任何一个因素。而是要应用所有可用的最佳做法,然后选择最适合当前情况的最佳做法。(Dropbox上的人们是Python优化功能最引人注目的例子之一。)

在本文中,我将概述许多常见的Python优化。有些是直接插入的措施,仅需将一项切换为另一项即可(例如更改Python解释器),但那些带来最大收益的措施将需要更详细的工作。

 

测量,测量,测量

正如古老的格言所说,您不能错过您没有测量的东西。同样,您无法找出为什么任何给定的Python应用程序都无法最佳运行的原因,而不是找出速度缓慢的实际原因。

从使用Python的内置cProfile模块进行简单分析开始,如果需要更高的精度或更深入的了解,请使用功能更强大的探查器。通常,从应用程序的基本功能级别检查中收集的见解提供了足够多的见解。(您可以通过profilehooks模块为单个功能提取配置文件数据。)

为什么应用程序的某个特定部分如此之慢,以及如何修复它,可能需要更多的挖掘工作。重点是缩小重点,建立硬性基准,并在可能的情况下跨各种使用情况和部署方案进行测试。不要过早优化。猜测使您无处可去。

 

 

上面从Dropbox链接的示例显示了配置文件的有用性。开发人员写道:“测量是告诉我们HTML转义起初很慢,而且如果不测量性能,我们将永远不会想到字符串插值会这么慢。”

记忆(缓存)重复使用的数据

一次只能保存一次结果,就永远不要做一千次。如果您有一个经常调用的函数可以返回可预测的结果,那么Python为您提供了将结果缓存到内存中的选项。随后返回相同结果的调用将几乎立即返回。

各种示例说明了如何执行此操作。我最喜欢的记忆几乎最少。但是Python内置了此功能。Python的本机库之一functools拥有@functools.lru_cachedecorator,它可以缓存对函数的n个最新调用。当您要缓存的值发生更改但在特定时间范围内相对静态时,这很方便。一天中最近使用过的物品清单将是一个很好的例子。

请注意,如果您确定对函数的各种调用将保持在合理的范围内(例如,100个不同的缓存结果),则可以改用@functools.cache 更高性能的方法。

将数学移至NumPy

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

NumPy也可以极大地加速相对非奇异的数学运算。该软件包可替代许多常见的Python数学运算(例如min和)max,这些运算比Python原始运算要快许多倍。

NumPy的另一个好处是可以更有效地使用内存存储大型对象,例如包含数百万个项目的列表。平均而言,如果使用传统的Python表示,大型对象(如NumPy中的对象)将占用所需内存的约四分之一。请注意,这有助于从正确 的作业数据结构开始,这是优化本身。

重写Python算法以使用NumPy需要一些工作,因为需要使用NumPy的语法声明数组对象。但是NumPy使用Python现有的习惯用法进行实际的数学运算(+,-等),因此从长远来看,切换到NumPy不会太令人迷惑。

将数学移至Numba

Numba是另一个用于加速数学运算的强大库。编写一些用于数字处理的Python代码,并用Numba的JIT(即时)编译器包装,然后生成的代码将以机器本机的速度运行。Numba不仅提供GPU驱动的加速(CUDA和ROC),而且具有特殊的“ nopython”模式,该模式试图通过尽可能不依赖Python解释器来最大化性能。

Numba还与NumPy携手合作,因此您可以两全其美-NumPy可以解决所有问题,Numba可以解决其他所有问题。

使用C库

NumPy使用C语言编写的库是一个很好的模仿策略。如果有满足您需要的现有C库,Python及其生态系统将提供多种选择来连接到该库并利用其速度。

最常见的方法是Python的ctypes 库。由于ctypes与其他Python应用程序(和运行时)广泛兼容,因此它是最好的起点,但它远非市面上唯一的游戏。该CFFI 项目提供了一个更优雅的界面C.用Cython(见下文)也可以用来包裹外部库,虽然不必学习用Cython的标记的成本。

需要注意的是:通过使跨C和Python边界的往返次数最小化,您将获得最佳结果。每次在它们之间传递数据时,都会对性能造成影响。如果您可以选择在紧密循环中调用C库还是将整个数据结构传递到C库并在那里进行循环处理,请选择第二个选项。您将减少域之间的往返次数。

 

转换为Cython

如果要提高速度,请使用C,而不要使用Python。但是对于Pythonista来说,编写C代码会带来很多干扰,例如学习C的语法,整理C工具链(现在我的头文件怎么了?)等等。

Cython允许Python用户方便地访问C的速度。现有的Python代码可以递增地转换为C:首先通过Cython将所述代码编译为C,然后添加类型注释以提高速度。

Cython不是魔杖。按原样转换为Cython的代码运行速度通常不会超过15%到50%,因为该级别的大多数优化都集中在减少Python解释器的开销上。当您为Cython模块提供类型注释时,最大的收益就是将相关代码转换为纯C语言。结果是提速可以快几个数量级。

绑定CPU的代码从Cython中受益最多。如果您已经进行了概要分析(您已经进行概要分析了,不是吗?),并且发现代码的某些部分占用了CPU的绝大部分时间,那么这些是进行Cython转换的极佳选择。与I / O绑定的代码(如长期运行的网络操作)将几乎不会从Cython中受益。

与使用C库一样,另一个重要的性能增强技巧是将与Cython的往返次数保持在最少。不要编写重复调用“ Cythonized”函数的循环。在Cython中实现循环并一次传递所有数据。

与多处理并行

传统的Python应用程序(在CPython中实现的那些应用程序)一次仅执行一个线程,以避免使用多个线程时出现的状态问题。这就是臭名昭著的全局解释器锁(GIL)。有充分的理由说明它的存在并不会使它变得更糟。

随着时间的推移,GIL的效率已大大提高,但核心问题仍然存在。CPython应用程序可以是多线程的,但是CPython确实不允许这些线程在多个内核上并行运行。

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

您仍然必须在流程之间手动管理状态。另外,启动多个Python实例并在其中传递对象的过程中不会涉及很多开销。但是对于长时间运行的进程,这些进程受益于跨内核的并行性,则多处理库很有用。

顺便说一句,使用C库的Python模块和软件包(例如NumPy或Cython)能够完全避免使用GIL。这是推荐他们提高速度的另一个原因。

知道你的图书馆在做什么

只需键入include xyz并利用无数其他程序员的工作,这是多么方便!但是您需要注意,第三方库可能会改变应用程序的性能,但并不总是会变得更好。

有时这会以明显的方式表现出来,例如当特定库中的模块构成瓶颈时。(再次,进行配置将有所帮助。)有时情况不太明显。示例:Pyglet是一个用于创建窗口化图形应用程序的便捷库,它会自动启用调试模式,这会严重影响性能,直到将其明确禁用。除非您阅读文档,否则您可能永远不会意识到这一点。阅读并得到通知。

注意平台

Python运行跨平台,但这并不意味着每个操作系统(Windows,Linux和OS X)的特性都在Python下被抽象化了。在大多数情况下,这意味着要了解平台特定内容,例如路径命名约定,并为此提供帮助功能。该pathlib的模块,例如,抽象了特定于平台的路径约定。

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

与PyPy一起运行

CPython是Python最常用的实现,它优先考虑兼容性而不是原始速度。对于想把速度放在首位的程序员,可以使用PyPy,它是一个配有JIT编译器的Python实现,可加快代码执行速度。

因为PyPy被设计为CPython的直接替代品,所以它是快速提高性能的最简单方法之一。许多常见的Python应用程序将完全按照原样在PyPy上运行。通常,应用程序越依赖“原始” Python,它越可能在未经修改的情况下在PyPy上运行。

但是,充分利用PyPy可能需要进行测试和研究。您会发现长期运行的应用程序从PyPy获得最大的性能提升,因为编译器会随时间分析执行情况。对于运行和退出的简短脚本,使用CPython可能会更好,因为性能提升不足以克服JIT的开销。

请注意,PyPy对Python 3的支持仍然落后几个版本。目前位于Python 3.2.5。使用最新的Python功能(例如异步和等待协同例程)的代码将无法正常工作。最后,使用ctypes的Python应用程序可能无法始终按预期运行。如果您编写的东西可能同时在PyPy和CPython上运行,则可能需要为每个解释器分别处理用例。

升级到Python 3

如果您使用的是Python 2.x,并且没有任何压倒一切的原因(例如,不兼容的模块),则应该跳转到Python 3,尤其是因为Python 2已过时并且不再受支持。

除了Python 3作为通用语言的未来之外,Python 3还提供了许多Python 2中没有的构造和优化。例如,Python 3.5通过使asyncandawait关键字成为语言语法的一部分,从而使异步编程的麻烦程度降低。Python 3.2对Global Interpreter Lock进行了重大升级,从而大大改善了Python处理多个线程的方式。

如果您担心Python版本之间的速度下降,该语言的核心开发人员最近重新启动了一个站点该站点用于跟踪各个版本之间的性能变化。

 

随着Python的成熟,动态语言和解释语言也普遍发展。您可以期待编译器技术的改进和解释器的优化,从而在未来几年为Python带来更快的速度。

就是说,更快的平台只会带您走远。任何应用程序的性能将始终更多地取决于编写该程序的人,而不是取决于执行该程序的系统。对于Pythonista来说幸运的是,丰富的Python生态系统为我们提供了许多选择,以使我们的代码运行更快。毕竟,只要足够快,Python应用程序就不必是最快的。

标签:11,Cython,技巧,Python,PyPy,应用程序,使用,NumPy
来源: https://blog.csdn.net/weixin_40478901/article/details/116846932