笔记|Python 性能开发|cProfile 使用技巧

cProfile 提供了 Python 程序的 稳定性性能分析;即通过监控所有函数调用、函数返回和异常事件,并对这些事件之间的间隔进行精确计时。实现统计程序的各个部分执行的频率和时间。cPorfile 的性能分析往往可以使用增加很小的处理开销,提供有关 Python 程序执行的大量运行时的统计信息。

cProfile 的文档:https://docs.python.org/zh-cn/3/library/profile.html

简单用法样例

当我们需要分析一个 Python 脚本的运行性能时,我们可以简单地将脚本入口函数封装起来,然后使用 cProfile.run() 方法执行这个函数。例如:

import cProfile

def main():
    """封装的脚本入口函数"""

if __name__ == "__main__":
   cProfile.run("main()")

cProfile 的 run 方法文档:https://docs.python.org/zh-cn/3/library/profile.html?#profile.run

如需添加全局命名空间和局部命名空间调用 run 方法,则可以使用 cProfilerunctx 方法。

cProfile 的 runctx 方法文档:https://docs.python.org/zh-cn/3/library/profile.html?#profile.runctx

上述脚本在脚本运行完成后,会在控制台打印类似信息:

         4140186 function calls (4071373 primitive calls) in 10.881 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      661    0.001    0.000    0.011    0.000 <__array_function__ internals>:177(all)
     8564    0.007    0.000    0.062    0.000 <__array_function__ internals>:177(amax)
     8562    0.006    0.000    0.065    0.000 <__array_function__ internals>:177(amin)
      656    0.001    0.000    0.011    0.000 <__array_function__ internals>:177(any)
......

其中:

列序号 列名 含义
1 ncalls 调用次数
2 tottime 在指定函数中消耗的总时间(不包括调用子函数的时间)
3 percall 是以 tottime 除以 ncalls 的商
4 cumtime 指定的函数及其所有子函数(从调用到退出)消耗的累积时间。这个数字对于递归函数来说是准确的。
5 percall cumtime 除以原始调用(次数)的商(即:函数运行一次的平均时间)
6 filename:lineno(function) 提供相应数据的每个函数

如果需要将上述结果排序,则可以使用 run 方法的 sort 参数,该参数需传入字符串或 SortKey 枚举类作为实参。排序参数 具体包括:

有效字符串参数 有效枚举参数 含义
"calls" SortKey.CALLS 调用次数
"cumulative" SortKey.CUMULATIVE 累积时间
"cumtime" - 累积时间
"file" - 文件名
"filename" SortKey.FILENAME 文件名
"module" - 文件名
"ncalls" - 调用次数
"pcalls" SortKey.PCALLS 原始调用计数
"line" SortKey.LINE 行号
"name" SortKey.NAME 函数名称
"nfl" SortKey.NFL 名称/文件/行
"stdname" SortKey.STDNAME 标准名称
"time" SortKey.TIME 内部时间
"tottime" - 内部时间

排序参数的文档:https://docs.python.org/zh-cn/3/library/profile.html?#pstats.Stats.sort_stats

使用 Profile 类进行性能分析

cProfile.Profile 类的文档:https://docs.python.org/zh-cn/3/library/profile.html?#profile.Profile

扫描二维码关注公众号,回复: 15053491 查看本文章

如需要更精确的性能分析,我们可以通过 Profile 类实现。该类支持直接格式化性能分析结果,而不需要将性能分析数据写入文件。该类有如下常用方法:

方法名 用途
enable() 开始收集分析数据。(用于精确控制分析范围)
disable() 停止收集分析数据。(用于精确控制分析范围)
create_stats() 停止收集分析数据,并在内部将结果记录为当前 profile。
print_stats(sort=-1) 根据当前性能分析数据创建一个 Stats 对象并将结果打印到 stdout。
dump_stats(filename) 将当前 profile 结果写入 filename。
run(cmd) 通过 exec() 对该命令进行性能分析。
runctx(cmd, globals, locals) 通过 exec() 并附带指定的全局和环境变量对该命令进行性能分析。
runcall(func, /, *args, **kwargs) func(*args, **kwargs) 进行性能分析。

需要注意的是,必须进行了 enable()run()runctx()runcall() 中任意一个方法后,profile 实例才能用于构造 Stats 类统计对象,否则会报错:

TypeError: Cannot create or construct a <class 'pstats.Stats'> object from <cProfile.Profile object at 0x000001BCE9C332E0>

使用 cProfile.Profile + pstat.Stats 进行性能分析的样例如下:

import cProfile
import pstats

def main():
    """封装的脚本入口函数"""
    preprocessing()  # 待分析函数执行前的初始化(不需要分析性能的部分)
    profiler.enable()
    processing()  # 待分析函数(需要被性能分析的部分)
    profiler.disable()
    reprocessing()  # 待分析函数执行后的后处理(不需要分析性能的部分)

if __name__ == "__main__":
    profiler = cProfile.Profile()  # 实例化 Profile 类
    main()  # 调用封装的脚本入口函数
    stats = pstats.Stats(profiler).sort_stats(pstats.SortKey.CUMULATIVE)  # 根据 profile 实例构造 Stats 类,并执行排序
    stats.print_stats()  # 将排序后的汇总统计结果打印到 stdout

在上例中,我们也可以使用 run()runctx()runcall() 等其他方法调用被分析函数。

使用 pstat 进行分析

pstats.Stats 类的文档:https://docs.python.org/zh-cn/3/library/profile.html?#pstats.Stats

Stats 类基于 filename 文件或 Profile 实例构造。输出会被打印到 stream 参数所指定的流中。该类有如下常用方法:

方法名 含义
strip_dirs() 去除文件的所有前导路径信息
add(*fileanmes) 将额外的性能分析信息累加到当前性能分析对象中
dump_stats(filename) 将当前性能分析对象中的信息写出到文件
sort_stats(*keys) 将当前性能分析对象中的记录排序(参数详见上文 排序参数 表)
reverse_order() 将当前性能分析对象中的记录倒序
print_callers(*restrictions) 打印哪些函数调用了 restrictions 函数
print_callees(*restrictions) 打印 restrictions 函数中调用了哪些函数
get_stats_profile() 返回一个 StatsProfile 实例

其中,需要注意的是:通过 get_stats_profile(),我们可以得到 StatsProfile 实例,该实例的 func_profiles 即字典格式的性能分析信息。如果需要对分析结果做进一步处理,则可以使用这个字典;但是该字典中没有保留每次调用的 callers 信息。

猜你喜欢

转载自blog.csdn.net/Changxing_J/article/details/129969026