Python 线程高CPU占用排查总结
1. 背景
- 线上进程CPU占用异常偏高。
- 希望快速定位到是哪一个线程导致的问题,并进一步追踪到具体Python代码位置。
2. 排查步骤
(1)确认CPU异常的进程
通过常规 top 或 htop 工具,找到高CPU占用的进程PID,比如 2608。
(2)确认线程视角下的情况
执行
1 | |
或
1 | |
切换到线程级别视角,查看哪个TID(线程ID)CPU占用最高。
注意:
top -H是动态实时监控。ps是静态一次性快照。
(3)将线程TID转成十六进制
因为Python解释器内部使用十六进制TID,需要转换,比如:
1 | |
例如线程ID是 3245,转换后是 0xca5。
(4)用GDB attach到目标进程
1 | |
成功后,执行:
1 | |
或者针对单一线程,切换到指定线程:
1 | |
pstack输出的是cpython的调用,查看很不优化
1 | |
(5)加载Python调试脚本,友好查看Python堆栈
1 | |
这样就能看到Python级别的调用栈了。
1 | |
3. 本次最终结果
最后通过
py-bt成功定位到了代码位置:/root/vscode-work/daily_code/busy_thread.py第18行- 处于
busy_thread()函数中 - 正在执行
pass死循环,占满CPU
4. 经验总结
| 项目 | 经验 |
|---|---|
| 问题归因 | 高CPU占用问题,常由死循环、频繁IO、竞争锁等引起 |
| 工具链掌握 | 熟练使用 top -H、ps -mp、gdb -p、py-bt |
| 注意事项 | 记得TID需要转16进制;Python要有对应的python-gdb.py脚本 |
| 小技巧 | py-bt能直接定位到Python代码层,比C层bt友好多了 |
补充
我自己用pyenv安装的python3.7没带 python-gdb.py
正常来说,python-gdb.py 是 Python 源码安装后在 lib-dynload/ 旁边的,像 /usr/lib/debug/... 或 /usr/lib/python3.x/ 目录中。
但是如果你用 pyenv 裸安装,默认是不会带这个调试脚本的(除非你自己加了参数 --with-pydebug 编译)。
解决方法是:
手动下载一份 python-gdb.py 脚本过来用。
Python 3.7.10 对应的 python-gdb.py 官方地址在 GitHub源码里:
👉 https://github.com/python/cpython/blob/3.7/Tools/gdb/libpython.py
步骤:
1 | |
然后在 gdb 里执行:
1 | |
就可以拿到 Python 代码级的调用栈了!!
Python 线程高CPU占用排查总结
https://luffy997.github.io/2024/07/15/Python-线程高CPU占用排查总结/