Skip to content

Programing Python Tools cProfile #318

@junxnone

Description

@junxnone

cProfile

  • Python 标准库自带的确定性性能分析器,实用的性能分析工具
  • 跟踪程序中每一个函数的调用次数、每次调用的耗时、函数执行的总时间等详细信息
  • 不会显著增加程序的运行开销
  • 记录每个函数的调用次数(ncalls)、累计耗时(tottime)、函数自身耗时(percall)、总耗时(cumtime)等核心指标。
指标 含义
ncalls 函数被调用的次数。如果是 n/m 格式,n 是总调用次数,m 是原生调用次数(排除递归)
tottime 函数自身执行的总时间(不包含调用其他函数的耗时),单位:秒
percall tottime /ncalls,即每次调用函数自身的平均耗时
cumtime 函数累计执行的总时间(包含调用其他函数的耗时),单位:秒
percall cumtime /ncalls,即每次调用的累计平均耗时
filename:lineno(function) 函数所在的文件、行号和函数名

UseCase

命令行直接运行(最简单) 分析整个脚本

python -m cProfile -s cumulative test.py
  • -s cumulative:按 cumtime(累计耗时)排序,优先显示最耗时的函数(最常用);
  • -o result.prof:将分析结果保存到 result.prof 文件,后续可读取分析;
  • -l:显示函数的行号信息。

代码内嵌入调用(灵活)

import cProfile
import pstats  # 用于解析和美化分析结果

# 定义需要分析的函数
def slow_function():
    total = 0
    for i in range(1000000):
        total += i
    return total

def main():
    # 1. 开始分析
    profiler = cProfile.Profile()
    profiler.enable()  # 启用分析

    # 执行需要分析的代码
    slow_function()

    # 2. 停止分析
    profiler.disable()  # 禁用分析

    # 3. 解析并打印结果(按累计耗时排序)
    stats = pstats.Stats(profiler)
    stats.sort_stats(pstats.SortKey.CUMULATIVE)  # 排序方式:累计耗时
    stats.print_stats(10)  # 只打印前10条结果

if __name__ == "__main__":
    main()

.prof 结果文件分析

脚本分析

import pstats

# 读取分析文件
stats = pstats.Stats("result.prof")
# 按累计耗时排序,打印前20条
stats.sort_stats("cumulative").print_stats(20)
# 还可以过滤结果,比如只显示包含 "slow" 的函数
stats.print_stats("slow")

过滤

  • pstats.Stats.print_stats() 方法可以接收正则表达式作为参数,用来过滤只显示文件名 / 函数名匹配的结果。
# 核心:过滤只显示 "my_module.py" 的函数(正则匹配文件名)
# 注意:如果是真实文件,写完整文件名(如 "my_module.py")或部分名称(如 "my_module")即可
print("=== 只显示 my_module.py 文件的函数统计 ===")
# 传入正则 "my_module",匹配所有文件名包含该字符串的函数
stats.print_stats("my_module", 100)  # 100 表示最多显示100条,可按需调整

# 【进阶】如果想过滤并保存过滤后的结果(可选)
# 先过滤,再打印/保存
stats = stats.strip_dirs()  # 去除路径前缀,方便匹配
stats = stats.filter_stats("my_module")  # 过滤出匹配的条目
stats.print_stats()  # 打印过滤后的所有结果
# 保存过滤后的结果到文件
stats.dump_stats("filtered_my_module.prof")
过滤需求 正则参数 效果
匹配精确文件名 "my_module.py" 只显示该文件的函数
匹配包含某字符串的文件 "my_module" 显示文件名含 "my_module" 的所有文件
匹配多个文件(或逻辑) "my_module | utils" 显示 my_module.py 或 utils.py 的函数
排除某文件(反向匹配) "^(?!.other)." 排除文件名含 "other" 的函数

排序

print("=== 按函数自身耗时(TOTTIME)排序 ===")
stats.sort_stats(pstats.SortKey.TOTTIME).print_stats(5)

# 2. 按「调用次数」排序(看哪个函数被调用最频繁)
print("\n=== 按调用次数(CALLS)排序 ===")
stats.sort_stats("calls").print_stats(5)  # 也可以用字符串别名

# 3. 按「累计平均耗时」排序(看单次调用整体开销)
print("\n=== 按累计平均耗时(CUM_PERCALL)排序 ===")
stats.sort_stats(pstats.SortKey.CUM_PERCALL).print_stats(5)

# 4. 多维度排序(先按调用次数,再按自身耗时)
print("\n=== 先按调用次数,再按自身耗时排序 ===")
stats.sort_stats("calls", "tottime").print_stats(5)


stats.sort_stats(pstats.SortKey.CALLS, reverse=True)  # 调用次数少的在前

排序方式 适用场景 分析目的
CUMULATIVE 定位整体性能瓶颈 找 “调用链中最耗时的函数”
TOTTIME 优化函数自身实现 找 “函数本身效率低” 的代码
CALLS 排查高频调用的轻量函数 找 “被调用次数过多” 的函数(可能重复执行)
PERCALL 分析单次调用的效率 对比同类函数的单次执行开销
CUM_PERCALL 评估单次调用的整体成本 找 “单次调用就占大量时间” 的函数

命令行分析

# 直接读取并按累计耗时排序显示
python -m pstats performance_report.prof
# 进入交互模式后,输入命令(比如 sort cumulative 按累计耗时排序,stats 10 显示前10条)
pstats> sort cumulative
pstats> stats 10
pstats> quit  # 退出交互模式

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions