当你写 Python 写得越来越多,就会突然发现------有些代码运行得慢得离谱,但自己却不知道"慢"到底发生在哪一步。 这时你就需要真正的性能分析工具上场了,而不是继续凭感觉优化。
本篇我们一起搞定两大核心工具:
- timeit:测函数执行时间
- cProfile:分析整段程序的性能瓶颈
最后我会给你一个完整的优化示例,让性能提升看得见。
1. 为什么代码会慢?
Python 是解释型语言,灵活但速度不是强项。 代码变慢常见原因包括:
- 不必要的循环
- 低效的数据结构
- 重复计算
- IO 阻塞(文件/网络)
- 第三方库使用不当
搞清楚瓶颈在哪里,是所有优化的起点。
2. 用 timeit 测局部性能:谁更快,一测便知
timeit 是个轻量级工具,非常适合比较小片段代码的速度。
例如:列表推导 vs for 循环,谁更快?
示例:用 timeit 测试代码片段
python
import timeit
# 列表推导
expr1 = "[i*i for i in range(1000)]"
# 普通循环
expr2 = """
result = []
for i in range(1000):
result.append(i*i)
"""
t1 = timeit.timeit(expr1, number=10000)
t2 = timeit.timeit(expr2, number=10000)
print("列表推导:", t1)
print("for 循环:", t2)
输出示例(依据电脑不同会变化)
makefile
列表推导: 0.32
for 循环: 0.45
你一下就看出列表推导更快。 这就是 timeit 的价值: 用数字说话,而不是猜测。
3. 用 cProfile 查整段程序的瓶颈:慢在哪,一清二楚
当你不确定慢的是哪部分时,就用 cProfile。
它会告诉你:
- 每个函数调用几次
- 每次耗时多久
- 总耗时
- 占比情况
超级适合分析中大型脚本。
示例:一个"看似没问题但其实很慢"的函数
python
def slow_func():
total = 0
for i in range(10000):
for j in range(10000):
total += i + j
return total
现在我们用 cProfile 分析:
python
import cProfile
cProfile.run("slow_func()")
你会看到类似:
bash
200000000 function calls in 3.821 seconds
ncalls tottime percall cumtime function
1 3.821 3.821 3.821 slow_func
一下就能看出: 问题全在 slow_func 本身,特别是双层循环。
4. 更清晰的结果?用 pstats 或 SnakeViz 可视化
默认输出较难读,你可以这样格式化:
python
import cProfile
import pstats
with cProfile.Profile() as pr:
slow_func()
stats = pstats.Stats(pr)
stats.sort_stats(pstats.SortKey.TIME)
stats.print_stats()
如果你想可视化展示(像瀑布图一样),可以安装 SnakeViz:
lua
pip install snakeviz
snakeviz output.prof
非常适合技术分享或团队协作。
5. 实战:一步步从 2.5s 优化到 0.01s
假设我们有一个脚本统计每行是否包含某些关键词:
python
def check_keywords(lines, keywords):
result = []
for line in lines:
for k in keywords:
if k in line:
result.append((line, k))
return result
分析:
- 双层循环
- 多次重复"是否包含"检查
- 关键词过多时会超级慢
现在,我们用 cProfile 跑一下:
python
cProfile.run("check_keywords(lines, keywords)")
你会看到绝大多数时间花在:
markdown
str.__contains__
因为你对每个 line、每个 keyword 都在做 in 操作。
优化方案:把关键词变成正则 OR 模式
python
import re
def fast_check_keywords(lines, keywords):
pattern = re.compile("|".join(map(re.escape, keywords)))
result = []
for line in lines:
m = pattern.search(line)
if m:
result.append((line, m.group()))
return result
再跑性能测试
从 2.5 秒 → 0.01 秒 优化效果巨大。
6. 性能优化原则:永远遵循这三条
① 优化前先量化
不要凭直觉优化 永远先用 timeit / cProfile 查看瓶颈。
② 优化数据结构
例如:
- 列表 → 集合(O(1) 查找)
- 循环计算 → 内建函数/向量化
③ 避免重复计算
缓存、预编译、提前转换格式,都能救命。
7. 总结
性能优化是 Python 开发者进阶的必备技能。 timeit 解决"小范围速度比较", cProfile 负责"全局瓶颈定位"。
只要你掌握:
- 定位
- 调试
- 替换更快的数据结构/算法
你就可以让脚本从"能跑"变成"飞快"。