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占用排查总结/