Python 性能剖析实战
代码跑得慢?不要瞎猜哪里慢。用 cProfile 宏观定位热点函数,用 line_profiler 逐行计时,用 memory_profiler 找内存泄漏。本文讲清 Python 性能剖析的完整工具链。
一、为什么需要性能剖析
「Premature optimization is the root of all evil」。优化前先测量,测量后再优化。性能剖析的核心思路:先宏观定位(哪个函数最慢),再微观下钻(哪一行最慢),最后针对性优化。
| 工具 | 粒度 | 开销 | 用途 |
|---|---|---|---|
| cProfile | 函数级 | 低 | 宏观找热点函数 |
| line_profiler | 行级 | 高 | 逐行计时找瓶颈 |
| memory_profiler | 行级 | 很高 | 内存分析找泄漏 |
二、cProfile 宏观剖析
python -m cProfile -s cumulative my_script.py
import cProfile
import pstats
def slow_function():
total = 0
for i in range(1000000):
total += i * i
return total
profiler = cProfile.Profile()
profiler.enable()
slow_function()
profiler.disable()
stats = pstats.Stats(profiler)
stats.sort_stats("cumulative")
stats.print_stats(10)
读表技巧:cumulative 列是函数含子调用的总耗时。先看 tottime(函数自身耗时)最高的那几个,那才是真正需要优化的地方。
三、line_profiler 逐行计时
pip install line_profiler
# 给要剖析的函数加 @profile 装饰器
@profile
def process_data(data):
result = []
for item in data:
transformed = item * 2 + 1
result.append(transformed)
return result
# 用 kernprof 运行
# kernprof -l -v my_script.py
四、memory_profiler 内存分析
pip install memory-profiler
from memory_profiler import profile
@profile
def load_large_data():
big_list = [i for i in range(1000000)]
return big_list
# python -m memory_profiler my_script.py
五、优化策略
# 优化前:循环里重复计算
def slow(n):
result = []
for i in range(n):
result.append(i ** 2 + i * 3)
return result
# 优化后:用列表推导
def fast(n):
return [i ** 2 + i * 3 for i in range(n)]
# 更优:用内置函数和 C 扩展
import numpy as np
def fastest(n):
arr = np.arange(n)
return arr ** 2 + arr * 3
六、常见误区
第一,不要过早优化。先让代码正确,再让代码快。第二,剖析时用真实数据。小样本跑出来的热点和生产环境完全不同。第三,剖析有开销,cProfile 会让程序慢 2-10 倍,line_profiler 慢 10-100 倍,不要在生产环境跑。
七、总结
Python 性能剖析三步法:cProfile 找热点函数、line_profiler 找慢行、memory_profiler 找内存问题。先测量再优化,用数据说话,不要凭感觉猜瓶颈。