QQ个性网:专注于分享免费的QQ个性内容

关于我们| 网站公告| 广告服务| 联系我们| 网站地图

搜索
编程 JavaScript Java C++ Python SQL C Io ML COBOL Racket APL OCaml ABC Sed Bash Visual Basic Modula-2 Logo Delphi IDL Groovy Julia REXX Chapel X10 Forth Eiffel C# Go Rust PHP Swift Kotlin R Dart Perl Ruby TypeScript MATLAB Shell Lua Scala Objective-C F# Haskell Elixir Lisp Prolog Ada Fortran Erlang Scheme Smalltalk ABAP D ActionScript Tcl AWK IDL J PostScript IDL PL/SQL PowerShell

9 个用于分析 Python 代码性能的优秀库

日期:2025/04/06 22:25来源:未知 人气:55

导读:从简单的计时器和基准测试模块到复杂的基于统计的框架,请利用这些工具来深入了解您的Python程序的性能。每种编程语言都有两种速度:开发速度和执行速度。Python 一直以来都更倾向于编写速度快而非运行速度快。尽管Python代码几乎总是足够快,但有时却不是这样。在这种情况下,你需要找出它为什么会落后,并采取措施解决。软件开发和工程领域有一条广受尊敬的名言:“测量,而不是猜测。”......

从简单的计时器和基准测试模块到复杂的基于统计的框架,请利用这些工具来深入了解您的Python程序的性能。

每种编程语言都有两种速度:开发速度和执行速度。Python 一直以来都更倾向于编写速度快而非运行速度快。尽管Python代码几乎总是足够快,但有时却不是这样。在这种情况下,你需要找出它为什么会落后,并采取措施解决。

软件开发和工程领域有一条广受尊敬的名言:“测量,而不是猜测。”在软件方面,很容易做出错误的假设,但这样做从来都不是一个好主意。关于实际程序性能的统计数据始终是追求使应用程序更快的第一最佳工具。

好消息是,Python提供了大量的包,你可以使用它们来分析应用程序的性能,并找出最慢的部分。这些工具从标准库中包含的简单单行命令到用于从正在运行的应用程序中收集统计数据的复杂框架不等。在这里,我介绍了其中九个最重要的工具,其中大多数跨平台运行,并且可以在PyPI或Python的标准库中轻松获得。

Time and Timeit

有时候,你只需要一个秒表。如果你只是想要测量运行需要数秒或数分钟的两段代码之间的时间,那么一个秒表就绰绰有余了。

Python标准库提供了两个用作秒表的功能。Time模块中的perf_counter函数调用操作系统的高精度计时器来获取任意的时间戳。在某个操作之前调用一次time.perf_counter,在操作之后调用一次,并计算两者之间的差值。这为你提供了一种不显眼、低开销(尽管也较为简单)的方式来测量代码执行时间。

Timeit模块尝试对Python代码执行类似实际基准测试的操作。timeit.timeit函数接受一段代码片段,运行多次(默认是100万次),并获取完成这些操作所需的总时间。它最适合用于确定单个操作或函数调用在紧密循环中的表现,例如,如果你想知道列表推导或传统列表构造在多次执行某项操作时是否更快。(通常情况下,列表推导更快。)

Time的缺点是它仅仅是一个秒表,而Timeit的主要用途是针对单个代码行或代码块的微基准测试。这些模块只有在处理孤立的代码时才有效。两者都不足以进行整个程序的分析——找出在成千上万行代码中程序花费最多时间的地方。

cProfile

Python标准库还包含了一个全程序分析分析器,即cProfile。当运行时,cProfile会跟踪你程序中每个函数的调用,并生成一个列表,列出哪些函数被调用得最频繁以及平均每次调用花费了多少时间。

cProfile有三个主要优势。第一,它包含在标准库中,因此在标准的Python安装中也可使用。第二,它对调用行为进行多种不同的统计,例如,它将函数调用本身指令所花费的时间与其他所有由该函数调用的调用所花费的时间分开。这使您可以确定一个函数本身是否缓慢,或者它是否在调用其他缓慢的函数。

第三,或许最好的一点是,你可以自由地约束cProfile。你可以对一个程序的整个运行进行采样,或者仅在选定函数运行时切换性能分析,以便更好地专注于该函数正在做什么以及它正在调用什么。这种方法最好在你已经将事情缩小了一些之后使用,但它可以节省你不得不在完整的性能分析跟踪中寻找的麻烦。

这就引出了cProfile的第一个缺点:它默认生成大量统计数据。在所有这些数据中寻找正确的信息可能会令人不知所措。另一个缺点是cProfile的执行模型:它会捕获每一个函数调用,从而产生大量的额外开销。这使得cProfile不适合在生产环境中对带有实时数据的应用程序进行性能分析,但对于开发过程中的性能分析则完全适用。

有关cProfile的更详细介绍,请参阅我们的另一篇文章。

FunctionTrace

FunctionTrace 在其基本轮廓上类似于 cProfile:您只需提供要分析的脚本名称,无需对代码进行任何仪器化操作,它就能生成随时间变化的函数调用和内存使用的详细跟踪。FunctionTrace 还能够处理多线程/多进程应用程序,而无需进行任何额外操作。有关 FunctionTrace 工作原理的技术细节,请参阅这篇文章。

与cProfile类似,FunctionTrace不使用采样;每一个动作都被记录下来。为了速度,性能分析组件是用Rust编写的。FunctionTrace的开发者声称,应用程序上施加的性能分析开销小于10%。

跟踪数据以JSON格式保存,因此从理论上讲,您可以使用任何应用程序来解析它。但FunctionTrace的一大优势是它使用Firefox Profiler,它可以在任何启用JavaScript的浏览器中运行,而不仅仅是Firefox,以将结果呈现为交互式图表。

请注意,FunctionTrace的性能分析组件在Windows上尚不可用;性能分析只能在Linux或Mac系统上进行。

Palanteer

Palanteer 是 Python 性能分析工具箱中相对较新的成员,可用于分析 Python 和 C++ 程序。如果您正在编写一个封装了自己创建的 C++ 库的 Python 应用程序,并希望对应用程序的两个组件获得最详细的见解,那么 Palanteer 将非常有用。最重要的是,Palanteer 会在桌面运行的图形用户界面应用程序中显示结果,随着您的程序运行实时更新。

为Python应用程序添加仪器与通过Palanteer运行应用程序一样简单,就像使用cProfile一样。函数调用、异常、垃圾回收和操作系统级别的内存分配都会被跟踪。如果你的应用程序的性能问题最终被证明与内存使用或对象分配有关,那么最后两个功能尤其有用。

Palanteer的一个重大缺点,至少在目前是这样,就是必须完全从头构建。目前还没有作为可安装的Python轮(wheels)提供的预编译二进制文件,因此你需要使用你的C++编译器,并且手头也要有CPython的源代码副本。

Pyinstrument

Pyinstrument的工作方式与cProfile类似,它会追踪你的程序并生成报告,关于占用大部分时间的代码。但Pyinstrument相对于cProfile有两个主要优势,使其值得一试。

首先,Pyinstrument不会尝试挂载每个函数调用的单个实例。它每毫秒对程序的调用堆栈进行采样,因此它不那么突兀,但仍足够敏感,可以检测到占用程序大部分运行时间的内容。

第二,Pyinstrument的报告更加简洁。它会显示你的程序中占用时间最多的顶级函数,这样你可以专注于分析最大的罪魁祸首。它还允许你快速找到这些结果,几乎不需要任何繁琐步骤。

Pyinstrument也拥有cProfile的许多便利之处。你可以将性能分析器作为应用程序中的一个对象使用,并记录选定函数的行为,而不是整个应用程序的行为。输出可以通过多种方式呈现,包括HTML。如果你想看完整的调用时间线,也可以要求这样做。

还有两个注意事项。首先,一些使用C编译扩展的程序,如使用Cython创建的程序,通过命令行调用Pyinstrument时可能无法正常工作。但如果Pyinstrument在程序本身中使用,例如通过用Pyinstrument profiler调用包装一个main()函数,那么它们就可以正常工作。

第二个注意事项:Pyinstrument对于在多个线程中运行的代码处理得不是很好。下面将详细介绍的Py-spy可能是更好的选择。

Py-spy

Py-spy,与Pyinstrument类似,通过在固定间隔采样程序调用堆栈的状态来工作,而不是尝试记录每个单独的调用。与PyInstrument不同,Py-spy的核心组件是用Rust编写的(Pyinstrument使用C扩展),并且与被分析的程序在不同的进程中运行,因此它可以安全地与生产中运行的代码一起使用。

这种架构使得Py-spy能够轻松地执行许多其他分析器无法做到的事情:分析多线程或子进程处理的Python应用程序。Py-spy还可以分析C扩展,但这些扩展需要使用符号进行编译才能发挥作用。对于使用Cython编译的扩展,生成的C文件需要存在才能收集适当的跟踪信息。

使用Py-spy检查应用程序有两种基本方法。一种方法是使用Py-spy的record命令运行应用程序,运行结束后生成火焰图。另一种方法是使用Py-spy的top命令运行应用程序,这将以与Unix top工具相同的方式实时更新和交互式显示Python应用程序的内部结构。还可以从命令行中导出单个线程堆栈。

Py-spy有一个很大的缺点:它主要用于从外部对一个完整的程序或其某些组件进行性能分析。它不允许您仅装饰和采样特定的函数。

Snakeviz

使用cProfile跟踪数据可视化的最常见方式是通过另一个标准库模块pstats。但问题是,pstats生成的是纯文本报告,并不总是提供进行性能分析统计所需的可视化类型。

Snakeviz 使用 cProfile 生成的数据,并生成易于阅读的、使用 HTML 渲染的交互式图形。有两种图表可供选择:"冰柱图"和"太阳射线图",它们都能一目了然地展示程序花费最多时间的地方。图表中的每个部分代表一个函数的调用时间。只需点击一个部分即可放大到该函数,并可以检查堆栈下方所有内容所花费的时间。

Snakeviz 还生成了一个可搜索和可排序的HTML表格视图,用于跟踪数据;这就像是pstats创建的跟踪的更交互式版本。即使你不关心图表,跟踪的表格视图本身也是一种非常强大的方法来理解cProfile数据。

Yappi

Yappi(“又一种Python分析器”)具有这里讨论的其他分析器中的许多最佳功能,也有一些其他分析器不提供的功能。PyCharm默认安装Yappi作为其首选分析器,因此使用该IDE的用户已经内置了访问Yappi的权限。

要使用Yappi,您需要在代码中添加指令来调用、启动、停止,并为性能分析机制生成报告。Yappi允许您在测量所需时间时选择“墙时间”或“CPU时间”。前者只是一个秒表;后者通过系统原生API记录CPU实际执行代码的时间,忽略I/O暂停或线程睡眠。CPU时间能让您最准确地了解某些操作(如执行数值代码)实际所需的时间。

Yappi在处理从线程中检索统计数据的方式上有一个非常不错的优点,即您不需要装饰线程代码。Yappi提供了一个函数,yappi.get_thread_stats(),它可以从您记录的任何线程活动中检索统计数据,然后您可以单独解析它们。统计数据可以以高粒度进行过滤和排序,类似于您可以使用cProfile所做的操作。

最后,Yappi 还可以对 greenlets 和协程进行剖析,这是许多其他剖析器难以或根本无法做到的事情。鉴于 Python 越来越广泛地使用异步隐喻,对并发代码进行剖析的能力是一个非常强大的工具。

本文内容根据www.infoworld.com网站上的文章总结和梳理而来, 如需了解更多信息,请访问该站点。

关于我们|网站公告|广告服务|联系我们| 网站地图

Copyright © 2002-2023 某某QQ个性网 版权所有 | 备案号:粤ICP备xxxxxxxx号

声明: 本站非腾讯QQ官方网站 所有软件和文章来自互联网 如有异议 请与本站联系 本站为非赢利性网站 不接受任何赞助和广告