Python编程实战:从 timeit 到 cProfile,一次搞懂代码为什么慢

当你写 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 负责"全局瓶颈定位"。

只要你掌握:

  • 定位
  • 调试
  • 替换更快的数据结构/算法

你就可以让脚本从"能跑"变成"飞快"。


相关推荐
阿华田51223 分钟前
如何基于Jupyter内核自研NoteBook
ide·python·jupyter·自研notebook
a程序小傲24 分钟前
京东Java面试被问:Fork/Join框架的使用场景
java·开发语言·后端·postgresql·面试·职场和发展
想用offer打牌28 分钟前
面试官问Redis主从延迟导致脏数据读怎么解决?
redis·后端·面试
W如Q扬44 分钟前
python程序使用supervisor启停
python·supervisor
Piar1231sdafa1 小时前
蓝莓果实检测与识别——基于decoupled-solo_r50_fpn_1x_coco模型实现
python
拾零吖1 小时前
Python 常用内置函数
python
行走的bug...1 小时前
python项目管理
开发语言·python
其美杰布-富贵-李1 小时前
tsai 完整训练流程实践指南
python·深度学习·时序学习·fastai
appearappear1 小时前
Mac 上重新安装了Cursor 2.2.30,重新配置 springboot 过程记录
java·spring boot·后端
m0_462605221 小时前
第N9周:seq2seq翻译实战-Pytorch复现-小白版
人工智能·pytorch·python