为什么要分析代码运行效率

分析代码的效率是计算机科学和软件开发中非常重要的一个方面,具体来说,时常分析你的代码有以下好处:

  • 效率分析可以帮助你编写更经济高效的代码,减少资源的浪费,从而提高系统的性能和可伸缩性。
  • 在设备资源紧张的情况,比如嵌入式开发、移动端开发等,高效的代码通常需要更少的硬件资源,这可以降低硬件采购和维护的成本。
  • 高效的代码还可能减少开发和维护成本,因为它更容易理解和调试。在大数据、人工智能和科学计算等领域,需要处理大规模数据集。高效的代码可以加快数据处理速度,从而支持更快的决策和分析。
  • 不高效的代码可能导致内存泄漏、CPU占用过高或其他资源浪费的问题。通过效率分析,可以及早发现和解决这些问题,确保应用程序稳定性和可靠性。
  • 在分析代码效率的过程中,你可能需要重新审视代码,找出潜在的性能问题和不必要的复杂性。这有助于提高程序员的解决和分析能力,在代码的宏观运行层面重新认识计算机执行程序的过程。

那么该如何分析你的代码呢,line by line review?这恐怕不太行,工欲善其事,必先利其器。趁手的工具可以协助你高效地完成分析工作。

评价代码的运行效率有很多种方法,比如:

  1. 基准测试:基准测试是一种通过运行代码并度量其性能来评估其效率的方法。你可以使用专门的性能测试工具或编写自己的基准测试套件来比较不同部分的代码性能。通过记录运行时间、内存使用等指标,可以直观地评估代码的效率。
  2. 时间复杂度分析:使用算法分析方法,你可以评估代码的时间复杂度。时间复杂度描述了代码的运行时间与输入规模之间的关系。通常,更低阶的时间复杂度表示更高效的算法或代码。
  3. 空间复杂度分析:类似于时间复杂度,空间复杂度分析可以帮助你评估代码在内存使用方面的效率。较低的空间复杂度表示代码使用较少的内存资源。
  4. 分析运行时间:在代码中插入时间记录代码段,然后运行代码并分析运行时间。这可以帮助你确定哪些部分的代码在运行时占用了大部分时间,从而重点优化那些部分。
  5. 分析内存使用:使用内存分析工具来监视代码的内存使用情况,以查找内存泄漏或大内存消耗的问题。这对于避免资源浪费和提高代码的稳定性很重要。

本文将介绍两个工具的使用,分别是py-spymemray

使用py-spy分析运行时间

py-spy 是 Python 程序的采样分析器。它可以让你直观地看到 Python 程序花费时间的情况,而无需重新启动程序或以任何方式修改代码。 py-spy 的开销极低:它为了速度而使用 Rust 编写(速度极快),并且不与分析的 Python 程序在同一进程中运行。这意味着 py-spy 可以安全地用于生产环境的 Python 代码。

py-spy是跨平台的,这意味着你可以在windows、linux、macos等平台使用。

1 安装py-spy

你可以直接通过 PyPI 安装:

1
pip install py-spy

另外的安装方式:

  • 如果你是 Rust 用户,还可以使用以下命令安装 py-spy: cargo install py-spy

  • 在 macOS 上,py-spy 在 Homebrew 中,可以使用 brew install py-spy 安装。

2 使用方法

py-spy 从命令行工作,它会获取要从中采样的程序的进程ID(PID)或要运行的 python 程序的命令行。最主要的三个命令分别是record, topdump

record

py-spy 支持使用 record 命令将分析代码的结果记录到文件中。例如,你可以通过以下方式生成 python 进程的火焰图:

1
2
3
py-spy record -o profile.svg --pid 12345
# OR
py-spy record -o profile.svg -- python myprogram.py

所谓火焰图,又称flamegraphs,它是一个可视化的文件,通常用于可视化分析软件的堆栈跟踪,使用它可以快速准确地识别出运行的代码路径。更多详细的信息可以看这里

可以使用 --format 参数更改文件格式以生成 speedscope 配置文件或原始数据。speedscope同样类似于火焰图,也是一个可视化的快速、交互式、基于网络的查看器。speedscope 允许你交互式地探索数据,以深入了解应用程序中缓慢的部分。

具体用法示例:

假设我们现在有一个待分析的算法程序foo.py,要分析它很简单,只需要执行以下命令:

1
py-spy record -o flamescope.json -f speedscope -- python3 foo.py

在这个命令中,-o flamescope.json表示输出文件名为flamescope.json的文件,它包含了分析的结果;-f speedscope表示输出speedscope格式的文件;-- python3 foo.py和正常运行python程序一样。

运行该命令,会执行一遍程序并记录运行时间,将分析结果保存到flamescope.json文件中。接下来,我们打开:https://www.speedscope.app/ 这个网页,将生成的文件导入到网页中,即可看到最终的火焰图。

record还有更多的选项,输入py-spy record --help可以查看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
USAGE:
py-spy record [OPTIONS] [python_program]...

ARGS:
<python_program>... commandline of a python program to run

OPTIONS:
-p, --pid <pid> PID of a running python program to spy on
--full-filenames Show full Python filenames, instead of shortening to show only the
package part
-o, --output <filename> Output filename
-f, --format <format> Output file format [default: flamegraph] [possible values: flamegraph,
raw, speedscope]
-d, --duration <duration> The number of seconds to sample for [default: unlimited]
-r, --rate <rate> The number of samples to collect per second [default: 100]
-s, --subprocesses Profile subprocesses of the original process
-F, --function Aggregate samples by function's first line number, instead of current
line number
--nolineno Do not show line numbers
-t, --threads Show thread ids in the output
-g, --gil Only include traces that are holding on to the GIL
-i, --idle Include stack traces for idle threads
-n, --native Collect stack traces from native extensions written in Cython, C or C++
--nonblocking Don't pause the python process when collecting samples. Setting this
option will reduce the performance impact of sampling, but may lead to
inaccurate results
-h, --help Print help information

top

top命令可以显示 Python 程序中哪些函数占用最多时间的实时视图,类似于 Unix 中的 top 命令:

1
2
3
py-spy top --pid 12345
# OR
py-spy top -- python foo.py

dump

还可以使用 dump 命令显示每个 python 线程的当前调用堆栈:

1
py-spy dump --pid 12345

使用memray分析内存使用

memray是一个 Python 的内存分析器。它可以跟踪 Python 代码、本机扩展模块和 Python 解释器本身中的内存分配。它可以生成多种不同类型的报告,帮助你分析捕获的内存使用数据。虽然通常用作 CLI 工具,但它也可以用作库来执行更细粒度的分析任务。

注意,该工具仅可在Linux和MacOS上使用,无法安装在其他平台上。

1 安装memray

直接通过 PyPI 安装:

1
pip install memray

2 使用方法

使用 Memray 的方法有很多种。最简单的方法是将其用作命令行工具来运行脚本、应用程序或库。

假设需要分析的代码文件为foo.py

1
python3 -m memray run foo.py

他会运行程序,并在程序所在位置输出一个二进制文件(如 memray-my_script.2369.bin ),接下来,你可以通过不同的方式进行分析。一种方法是使用 memray flamegraph 命令生成火焰图:

1
python3 -m memray flamegraph my_script.2369.bin

这将生成一个 HTML 文件,其中包含内存使用情况的火焰图,接下来,只需要使用浏览器打开该 HTML 文件即可查看分析结果。

另外一种使用方式类似于top,官方称之为实时模式。它可以在基于终端的界面中运行脚本或模块,允许你在运行时交互式检查其内存使用情况。这对于调试需要很长时间运行或表现出多种复杂内存模式的脚本或模块非常有用。你可以使用 --live 选项在实时模式下运行脚本或模块:

1
python3 -m memray run --live foo.py

更多详细的用法,请查看官方文档

总之,评价代码的运行效率需要综合使用多种方法和工具。这些方法可以帮助你找出性能问题并进行必要的优化,以确保代码在运行时高效、稳定和可扩展性。