Python 性能分析工具
性能分析帮助定位代码瓶颈,指导优化方向。
cProfile 基本使用
Python
import cProfile
def slow_function():
total = 0
for i in range(1000000):
total += i
return total
# 直接运行分析
cProfile.run('slow_function()')
输出示例:
Python
4 function calls in 0.084 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.084 0.084 0.084 0.084 <string>:1(<module>)
1 0.000 0.000 0.084 0.084 test.py:1(slow_function)
输出字段说明
| 字段 | 说明 |
|---|---|
| ncalls | 调用次数 |
| tottime | 函数自身耗时(不含子函数) |
| percall | tottime/ncalls |
| cumtime | 累计耗时(含子函数) |
| filename:lineno | 文件名和行号 |
排序输出
Python
import cProfile
# 按累计时间排序
cProfile.run('slow_function()', sort='cumtime')
# 按调用次数排序
cProfile.run('slow_function()', sort='calls')
# 按自身时间排序
cProfile.run('slow_function()', sort='time')
Profile 对象方式
Python
import cProfile
import pstats
profiler = cProfile.Profile()
profiler.enable()
# 执行代码
slow_function()
profiler.disable()
# 输出统计
stats = pstats.Stats(profiler)
stats.sort_stats('cumtime')
stats.print_stats(10) # 打印前10条
保存分析结果
Python
import cProfile
profiler = cProfile.Profile()
profiler.run('slow_function()')
# 保存到文件
profiler.dump_stats('profile_result.prof')
# 加载分析
import pstats
stats = pstats.Stats('profile_result.prof')
stats.print_stats()
timeit 精确计时
Python
import timeit
# 测试代码片段
time = timeit.timeit('sum(range(1000))', number=10000)
print(f"耗时: {time:.4f}s")
# 测试函数
def test_func():
return sum(range(1000))
time = timeit.timeit(test_func, number=10000)
print(f"耗时: {time:.4f}s")
timeit 精确测量
Bash
import timeit
# 使用 setup 设置环境
time = timeit.timeit(
'"".join(str(i) for i in range(100))',
number=1000,
setup='import string'
)
# repeat 多次测量取最佳
times = timeit.repeat(
'sum(range(1000))',
number=10000,
repeat=5
)
print(f"最佳: {min(times):.4f}s")
print(f"平均: {sum(times)/len(times):.4f}s")
命令行使用
Python
# cProfile 命令行
python -m cProfile -s cumtime script.py
# timeit 命令行
python -m timeit "sum(range(1000))"
python -m timeit -n 1000 -r 5 "sum(range(1000))"
性能对比示例
Python
import timeit
# 对比列表推导式 vs map
list_comp = timeit.timeit('[x**2 for x in range(1000)]', number=10000)
map_func = timeit.timeit('list(map(lambda x: x**2, range(1000)))', number=10000)
print(f"列表推导式: {list_comp:.4f}s")
print(f"map函数: {map_func:.4f}s")
# 对比字符串拼接
join_time = timeit.timeit(
'"".join([str(i) for i in range(100)])',
number=10000
)
plus_time = timeit.timeit(
's=""\nfor i in range(100): s+=str(i)',
number=10000
)
print(f"join拼接: {join_time:.4f}s")
print(f"+拼接: {plus_time:.4f}s")
分析装饰器
text
import cProfile
import functools
def profile(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
profiler = cProfile.Profile()
profiler.enable()
result = func(*args, **kwargs)
profiler.disable()
profiler.print_stats(sort='cumtime')
return result
return wrapper
@profile
def analyzed_function():
return sum(range(1000000))
analyzed_function()
工具对比
| 工具 | 用途 | 特点 |
|---|---|---|
| cProfile | 函数级分析 | 细粒度瓶颈定位 |
| timeit | 代码片段计时 | 精确测量小代码 |
| profile | 纯Python分析 | cProfile的Python版本 |
要点总结
cProfile.run()快速分析代码性能- tottime 是函数自身耗时,cumtime 是累计耗时
sort='cumtime'按累计时间排序定位瓶颈- Profile 对象可保存分析结果到文件
timeit.timeit()精确测量代码片段timeit.repeat()多次测量取稳定结果- 命令行
-m cProfile分析脚本 - 性能对比选择最优实现方案
📝 发现内容有误?点击此处直接编辑