最近帮朋友优化一个爬虫项目,跑起来慢得像蜗牛。他一开始以为是网络问题,结果一通排查下来,发现是代码里几个函数拖了后腿。这种情况太常见了,写Python容易,写高效的Python可没那么简单。这时候就得靠性能分析来“揪出元凶”。
cProfile:自带的性能侦察兵
Python自带的cProfile模块,不用额外安装,直接就能用。比如你有个叫main.py的脚本,想看看它执行时到底卡在哪,命令行这么跑:
python -m cProfile main.py
输出结果会列出每个函数调用了多少次、花了多少时间。重点关注tottime和cumtime这两列,前者是函数本身耗时,后者包含它调用的其他函数的时间。哪个函数时间特别长,基本就是它的问题。
line_profiler:细看到每一行
有时候函数整体不慢,但里面某一行特别拖沓,比如一个不该放在循环里的数据库查询。这时候cProfile粒度不够,得上line_profiler。
先装一下:pip install line_profiler,然后在要分析的函数上加个@profile装饰器:
@profile
def process_data():
data = []
for i in range(10000):
data.append(i ** 2) # 这一行其实很快
return data
接着用kernprof运行:kernprof -l -v main.py,它会逐行显示每行代码的执行时间和次数,一眼看出瓶颈在哪。
memory_profiler:内存也不能忽视
性能不只是速度,还有内存。有个数据处理脚本,跑着跑着就把服务器内存吃光了。用memory_profiler一查,发现是中间缓存了一个超大的临时列表。
同样加@profile,然后运行:
python -m memory_profiler main.py
输出会显示每一行执行后的内存占用变化。突然飙升的那一行,八成就是内存泄漏或者不合理加载的地方。
实际案例:从6秒到0.6秒
之前那个爬虫,原本每次请求后都用正则反复匹配同一个页面内容,还用了re.compile()放在循环里。line_profiler显示这一块占了80%时间。改成预编译正则并复用,再把重复匹配提取成一次操作,总耗时直接从6秒降到不到1秒。
工具不是万能的,关键是怎么看数据。别一上来就想着换语言或者加机器,先把Python自己的分析工具用明白,很多时候问题就藏在你看不起眼的那几行代码里。