py-spy 附加失败主因是系统权限限制及符号缺失:linux/macos 需 ptrace 权限(sudo 或调优内核参数),macos 需禁用 sip;火焰图全为 ??? 说明未加载 python 符号,应使用官方 cpython 且未 strip;死锁常表现为 epoll_wait/select 卡住、栈顶平坦,需结合 py-spy top/dump 查锁对象;多进程须单独 attach 子进程或启用 --subprocesses;函数名截断多因装饰器或 c 扩展,可加 --native 辅助分析;根本难点在于将底层阻塞与业务代码精准关联。

Py-Spy 附加失败:进程没权限或没符号
Linux/macOS 下 py-spy 默认需要 ptrace 权限,普通用户直接附加常报 Operation not permitted 或静默失败。不是代码问题,是系统限制。
- Linux 上临时解决:用
sudo py-spy record -p <code>PID--duration 30 -o flame.svg(注意PID要替换成真实进程号) - 更稳妥的做法:启动 Python 进程前加
prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY),但需修改源码;或改用--nonblocking模式降低侵入性 - macOS 上需关闭 SIP,或在开发机上用
sudo启动py-spy;否则即使进程是自己启的,也会被拦 - 如果火焰图里全是
???或地址(如0x7ff...),说明没加载 Python 符号——确认用的是官方 CPython(非 PyO3/conda 自编译等变体),且没 strip 过二进制
火焰图看不出死锁:只看到 select、epoll_wait 或空栈
Py-Spy 抓的是采样时刻的调用栈,而死锁往往卡在系统调用或锁等待点,上层 Python 帧可能已退出,只剩 C 层阻塞。这时候火焰图顶部平坦、无明显热点,不代表没卡住。
- 先看
py-spy top -p <code>PID实时观察线程状态:如果某线程长时间停在threading.Lock.acquire、queue.get或socket.recv,就是线索 - 用
py-spy dump -p <code>PID查所有线程完整栈,重点找重复出现的锁对象 ID(比如<lock object at></lock>),多个线程卡在同一个地址大概率是它 - 火焰图里若大量样本落在
time.sleep或threading.Condition.wait,别急着忽略——可能是条件未满足导致的假性“空转”,得结合业务逻辑判断是否该唤醒没唤醒
Python 多进程场景下只看到主进程,子进程没采到
py-spy 默认只 attach 指定 PID,而 multiprocessing 子进程是全新进程,PID 不同,不手动指定就漏掉。死锁常发生在子进程通信环节(比如 Queue.put 阻塞),光看主进程会误判。
- 用
ps aux | grep python或pgrep -P <code>PID找出全部子进程 PID,再逐个py-spy record -p <code>CHILD_PID-o child-flame.svg - 如果子进程由
multiprocessing.spawn启动(如 Windows/macOS 默认),它们可能共享父进程的部分环境,但仍是独立进程,必须单独 attach - 注意:子进程可能启动快、结束快,采样窗口太短会错过;建议用
--duration 60并配合--subprocesses参数(v0.9.0+ 支持),自动抓本进程及其子 Python 进程
生成的火焰图里函数名被截断或显示为 <method></method>
这是 Py-Spy 无法解析帧对象中的函数名字段,常见于使用了装饰器(尤其 @cached_property、@dataclass 自动生成的方法)、C 扩展模块或某些异步框架(如 FastAPI 的依赖注入栈)。
立即学习“Python免费学习笔记(深入)”;
- 不用硬解,优先看栈深度和调用路径:即使显示
<method></method>,它上面是谁、下面是谁,仍能定位上下文 - 加
--native参数让 Py-Spy 同时采集 C 层栈,有时能暴露底层阻塞点(如pthread_cond_wait) - 如果大量
<method></method>出现在 asyncio 相关位置,检查是否用了loop.run_in_executor卡住线程池,此时要结合concurrent.futures状态分析
真正难的不是画出火焰图,而是把图里那个扁平的 epoll_wait 块,和你代码里第 217 行那个忘了 await 的协程调用对上号——这中间差的是对运行时模型的理解,不是工具能自动补全的。










