站点图标 兰玉磊的个人博客

使用Profilers来分析Python程序的性能瓶颈

profile分析器简介

cProfile 和 profile 提供了 Python 程序的 确定性性能分析 。 profile 是一组统计数据,描述程序的各个部分执行的频率和时间。这些统计数据可以通过 pstats 模块格式化为报表。

Python 标准库提供了同一分析接口的两种不同实现:

注解

profiler 分析器模块被设计为给指定的程序提供执行概要文件,而不是用于基准测试目的( timeit 才是用于此目标的,它能获得合理准确的结果)。这特别适用于将 Python 代码与 C 代码进行基准测试:分析器为Python 代码引入开销,但不会为 C级别的函数引入开销,因此 C 代码似乎比任何Python 代码都更快。

实时用户手册

本节是为 “不想阅读手册” 的用户提供的。它提供了非常简短的概述,并允许用户快速对现有应用程序执行评测。

要分析采用单个参数的函数,可以执行以下操作:

import cProfile
import re
cProfile.run('re.compile("foo|bar")')

(如果 cProfile 在您的系统上不可用,请使用 profile 。)

上述操作将运行 re.compile() 并打印分析结果,如下所示:

      197 function calls (192 primitive calls) in 0.002 seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    0.001    0.001 <string>:1(<module>)
     1    0.000    0.000    0.001    0.001 re.py:212(compile)
     1    0.000    0.000    0.001    0.001 re.py:268(_compile)
     1    0.000    0.000    0.000    0.000 sre_compile.py:172(_compile_charset)
     1    0.000    0.000    0.000    0.000 sre_compile.py:201(_optimize_charset)
     4    0.000    0.000    0.000    0.000 sre_compile.py:25(_identityfunction)
   3/1    0.000    0.000    0.000    0.000 sre_compile.py:33(_compile)

第一行显示监听了197个调用。

在这些调用中,有192个是 原始的 ,这意味着调用不是通过递归引发的。

下一行: Ordered by: standard name ,表示最右边列中的文本字符串用于对输出进行排序。

列标题包括:

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

如果第一列中有两个数字(例如3/1),则表示函数递归。第二个值是原始调用次数,第一个是调用的总次数。请注意,当函数不递归时,这两个值是相同的,并且只打印单个数字。

profile 运行结束时,打印输出不是必须的。也可以通过为 run() 函数指定文件名,将结果保存到文件中:

import cProfile
import re
cProfile.run('re.compile("foo|bar")', 'restats')

pstats.Stats 类从文件中读取 profile 结果,并以各种方式对其进行格式化。

cProfile 和 profile 文件也可以作为脚本调用,以分析另一个脚本。例如:

python -m cProfile [-o output_file] [-s sort_order] (-m module | myscript.py)

退出移动版