cprofile 是项目中唯一值得使用的性能分析工具,因其低开销和高精度;需用 -s cumulative 排序、-o 保存二进制文件,配合 pstats 交互式分析定位瓶颈,且须注意异步、多进程及 i/o 限制。

cProfile 是唯一值得在项目里用的性能分析入口,profile 模块纯 Python 实现、开销大,开发调试都该避开它。
python -m cProfile 命令行启动最省事
直接运行 python -m cProfile -s cumulative your_script.py 就能拿到按累计耗时排序的函数列表,不用改代码、不依赖任何包。关键参数必须带 -s cumulative,否则默认按函数名排序,根本看不出谁拖慢了整体。
-
-o profile.out一定要加——把结果存成二进制文件,后续才能用pstats精确筛选;直接输出到终端会截断、丢失调用链 - 别信
tottime字段:像json.loads()自身耗时可能只有 0.001s,但被循环调用 5000 次,cumtime才暴露真实代价 - 第三方库(如
requests、sqlalchemy)会刷屏,进pstats后先用filter your_module.py锁定自己代码范围
Web 服务里手动包裹请求逻辑要防覆盖和泄漏
在 Flask/FastAPI 路由里嵌 cProfile.Profile() 很常见,但漏掉 profiler.disable() 或文件名没隔离,会导致多请求统计混在一起、内存暴涨甚至进程卡死。
- 必须显式调用
profiler.disable(),不能靠__del__或上下文管理器——异步或异常路径下容易失效 - 文件名得含
os.getpid()和time.time(),比如profile_{os.getpid()}_{int(time.time())}.prof;Uvicorn 多 worker 下不加 pid 就是互相覆盖 - 别在 async 函数里直接 profile,
await切换不会被计入函数耗时,看到的全是select.select或threading.Lock.acquire—— 这是调度开销,不是你的业务瓶颈
pstats 交互式分析才是关键环节
生成 profile.out 只是第一步,真正定位靠 python -m pstats profile.out 进入交互后的一系列命令。离线分析不可跳过,实时看控制台输出基本无效。
- 首先进
sort cumulative,再top 15,找cumtime占比超 20% 的函数——它大概率就是瓶颈源头 - 对高
cumtime函数执行callers function_name,看是不是被某个 for 循环反复调用;如果是,优化点不在函数内部,而在调用频次 - 如果所有
cumtime都很低但总耗时很长,说明卡在 I/O(数据库查询、HTTP 请求)或系统调用上,cProfile 根本不计时,得立刻切py-spy或strace
真正容易被忽略的是:cProfile 只统计 CPU 时间,不反映 GC 停顿、磁盘等待、网络延迟这些真实阻塞点。一旦发现 profile 报告里“没热点但就是慢”,别再折腾排序参数,马上换工具查系统调用栈。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











