本文目录导读:
是的,cProfile 是 Python 内置的性能分析工具,可以精确定位代码中的性能瓶颈,以下是快速定位的完整方法:
基本使用方法
命令行方式(最简单)
# 分析整个脚本 python -m cProfile your_script.py # 限制输出行数 python -m cProfile -s time your_script.py | head -20
代码中嵌入
import cProfile
import pstats
def your_function():
# 你的代码
pass
# 方式1:直接运行函数
cProfile.run('your_function()')
# 方式2:更详细的输出
profiler = cProfile.Profile()
profiler.enable()
your_function()
profiler.disable()
# 保存分析结果
profiler.dump_stats('profile_stats.prof')
分析输出结果
关键列解释:
- ncalls: 函数调用次数
- tottime: 函数自身执行时间(不含子函数)
- percall: tottime/ncalls
- cumtime: 函数累计执行时间(含子函数)
- percall: cumtime/ncalls
# 排序查看
p = pstats.Stats('profile_stats.prof')
p.sort_stats('cumtime').print_stats(20) # 按累计时间排序,显示前20行
可视化分析
使用 snakeviz(推荐)
# 安装 pip install snakeviz # 生成可视化报告 python -m cProfile -o output.prof your_script.py snakeviz output.prof
生成火焰图
import cProfile
import pstats
import io
# 收集数据
profiler = cProfile.Profile()
profiler.enable()
# 你的代码
profiler.disable()
# 导出为可读格式
s = io.StringIO()
ps = pstats.Stats(profiler, stream=s).sort_stats('cumtime')
ps.print_stats()
print(s.getvalue())
实战示例
假设有以下慢速代码:
import time
import cProfile
def slow_function():
result = []
for i in range(10000):
result.append(i ** 2)
time.sleep(0.001) # 模拟慢操作
return result
def fast_function():
return [i ** 2 for i in range(10000)]
def main():
a = slow_function()
b = fast_function()
# 分析
cProfile.run('main()', sort='cumtime')
输出示例:
10003 function calls in 10.234 seconds
Ordered by: cumulative time
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 10.234 10.234 example.py:13(main)
1 0.001 0.001 10.233 10.233 example.py:3(slow_function)
10000 0.000 0.000 10.000 0.001 {built-in method time.sleep}
1 0.001 0.001 0.001 0.001 example.py:10(fast_function)
快速定位技巧
只关注热点函数
p = pstats.Stats('output.prof')
p.sort_stats('time').print_stats(10) # 显示最耗时的10个函数
过滤特定模块
# 只显示你的代码,排除系统库
p.print_callers('your_module.py')
比较两次运行
# 保存两次结果 # 然后比较
最佳实践
- 先全局分析:使用命令行快速查看整体情况
- 聚焦热点:关注 cumtime 最大的函数
- 检查调用次数:高 ncalls 的函数可能值得优化
- 区分自己和第三方:优先优化自己的代码
- 使用可视化工具:snakeviz 比文本输出直观得多
常见瓶颈类型
- 重复计算:函数被调用过多(高 ncalls)
- 算法效率:cumtime 高但 tottime 也不低
- I/O 等待:time.sleep, 数据库查询等
- 内存分配:频繁创建大对象
通过 cProfile + 可视化工具,通常几分钟内就能定位到性能瓶颈,效率远高于手动加 print 调试。