找回密码
 立即注册
首页 业界区 业界 [python] 代码性能分析工具line_profiler使用指北 ...

[python] 代码性能分析工具line_profiler使用指北

戈森莉 前天 21:30
代码分析能够评估各部分代码的时间消耗,即进行时间复杂度分析。通过这一过程,我们可以识别影响整体运行效率的关键部分,从而更高效地利用底层计算资源。此外,代码分析也可用于评估内存使用情况,即空间复杂度,以优化内存管理并提升其使用效率。本文主要关注时间复杂度分析的内容。
Python默认提供了两个实用的性能分析库:cProfile和profile。它们能够按函数维度输出性能数据,但无法展示函数内部逐行的执行详情。而Python公开库line_profiler弥补了这一不足,使我们能够清晰查看代码中每一行的执行耗时。
line_profiler是Python中一款强大的逐行性能分析工具,能够帮助开发者精确定位代码中的性能瓶颈。对于初学者而言,该工具在代码优化过程中具有重要价值。line_profiler官方开源仓库见:line_profiler-github,官方文档见:line_profiler-doc。
1.jpeg

本文将提供一份简单易用的line_profiler教程,重点讲解其在代码中的使用方法;命令行端的使用方式,可参考:Line by Line Profiling of Python Code。line_profiler安装命令如下:
pip install line_profiler
  1. import line_profiler
  2. # 查看line_profiler版本
  3. line_profiler.__version__
复制代码
  1. '4.1.3'
复制代码
目录

  • 1 使用入门

    • 1.1 基础使用
    • 1.2 进阶使用

  • 2 参考

1 使用入门

1.1 基础使用

简单调用
以下代码为示例耗时代码,它会经过不同时长的休眠,随后生成大量随机数并计算其平均值。
  1. import time
  2. import math
  3. import random
  4. def power_sum(a, b):
  5.     """计算a到b的平方和"""
  6.     return sum(math.pow(x, 2) for x in range(a, b))
  7. def calculate(sleep_time):
  8.     time.sleep(sleep_time)
  9.     # 随机范围计算平方和的平均值
  10.     start = 0
  11.     end = 1000000
  12.     total = power_sum(start, end)
  13.     return total / (end - start)
  14. def test_func():
  15.     calculate(sleep_time=1)
  16.     calculate(sleep_time=3)
  17.     calculate(sleep_time=5)
复制代码
使用line_profiler分析函数运行时间,首先创建一个LineProfiler对象,再通过调用该实例并传入目标函数,生成一个分析器。执行该分析器即可自动运行目标函数。函数执行完成后,调用分析器实例的print_stats方法即可输出分析结果。注意:直接调用print_stats仅会显示目标函数中顶层代码的运行时间。
  1. from line_profiler import LineProfiler
  2. lprofiler = LineProfiler()
  3. lp_wrapper = lprofiler(test_func)
  4. lp_wrapper()
  5. lprofiler.print_stats()
复制代码
  1. Timer unit: 1e-09 s
  2. Total time: 9.92798 s
  3. File: /tmp/ipykernel_14853/1826372064.py
  4. Function: test_func at line 17
  5. Line #      Hits         Time  Per Hit   % Time  Line Contents
  6. ==============================================================
  7.     17                                           def test_func():
  8.     18         1 1242792669.0    1e+09     12.5      calculate(sleep_time=1)
  9.     19         1 3340978413.0    3e+09     33.7      calculate(sleep_time=3)
  10.     20         1 5344205767.0    5e+09     53.8      calculate(sleep_time=5)
复制代码
print_stats输出的各列含义如下:

  • Timer unit
    时间单位(默认自动根据代码执行速度调整),常见的有秒(s)、毫秒(ms,1e-3 秒)、微秒(us,1e-6 秒)、纳秒(ns,1e-9 秒)
  • Total time
    整个函数的总执行时间
  • Line #
    代码行号
  • Hits
    该行代码的执行次数(循环体通常次数较多,函数定义、return等语句通常为1次)
  • Time
    该行代码的累计执行时间(单位同Timer unit),包含该行调用的所有函数耗时
  • Per Hit
    每次执行该行代码的平均时间,计算公式为Time / Hits
  • % Time
    该行耗时占函数总时间的百分比,是识别性能瓶颈的关键指标,需重点关注占比较高的行,循环体通常是性能瓶颈所在
  • Line Contents
    代码内容本身
深层调用
使用line_profiler分析函数运行时间时,如需同时分析其调用的下一层或更深层函数,则需在创建LineProfiler对象时明确指定所有待追踪的目标函数及其子函数。此时,line_profiler会为每个被监控的函数分别生成分析报告,且父函数的耗时统计中将包含所有子函数的执行时间。
  1. from line_profiler import LineProfiler
  2. lprofiler = LineProfiler()
  3. lprofiler.add_function(calculate)
  4. lprofiler.add_function(power_sum)
  5. lp_wrapper = lprofiler(test_func)
  6. lp_wrapper()
  7. # 追踪的函数列表
  8. lprofiler.functions
  9. # output_unit:设置输出单位,可选值,1(秒),1e-3(毫秒),1e-6(微秒)
  10. # details:是否显示详细的行级分析信息,默认是
  11. # summarize:是否对结果进行汇总,默认否
  12. # rich:是否使用富文本格式输出,默认否
  13. lprofiler.print_stats(output_unit=1e-3, details=True, summarize=False, rich=False)
复制代码
  1. Timer unit: 0.001 s
  2. Total time: 0.756163 s
  3. File: /tmp/ipykernel_14853/1826372064.py
  4. Function: power_sum at line 5
  5. Line #      Hits         Time  Per Hit   % Time  Line Contents
  6. ==============================================================
  7.      5                                           def power_sum(a, b):
  8.      6                                               """计算a到b的平方和"""
  9.      7         3        756.2    252.1    100.0      return sum(math.pow(x, 2) for x in range(a, b))
  10. Total time: 9.76247 s
  11. File: /tmp/ipykernel_14853/1826372064.py
  12. Function: calculate at line 9
  13. Line #      Hits         Time  Per Hit   % Time  Line Contents
  14. ==============================================================
  15.      9                                           def calculate(sleep_time):
  16.     10         3       9006.3   3002.1     92.3      time.sleep(sleep_time)
  17.     11                                               # 随机范围计算平方和的平均值
  18.     12         3          0.0      0.0      0.0      start = 0
  19.     13         3          0.0      0.0      0.0      end = 1000000
  20.     14         3        756.2    252.1      7.7      total = power_sum(start, end)
  21.     15         3          0.0      0.0      0.0      return total / (end - start)
  22. Total time: 9.76259 s
  23. File: /tmp/ipykernel_14853/1826372064.py
  24. Function: test_func at line 17
  25. Line #      Hits         Time  Per Hit   % Time  Line Contents
  26. ==============================================================
  27.     17                                           def test_func():
  28.     18         1       1250.6   1250.6     12.8      calculate(sleep_time=1)
  29.     19         1       3253.7   3253.7     33.3      calculate(sleep_time=3)
  30.     20         1       5258.2   5258.2     53.9      calculate(sleep_time=5)
复制代码
使用装饰器调用
这种以分析器实例作为装饰器的方式,实质上是一种语法糖。它将被装饰的函数包装为一个代理,使分析器能够监听每次调用,从而精确记录其每一行的执行情况。
[code]from line_profiler import LineProfiler# 创建性能分析器lprofiler = LineProfiler()# 使用装饰器标记要分析的函数@lprofilerdef fibonacci(n):    if n

相关推荐

您需要登录后才可以回帖 登录 | 立即注册