py-spy 是无侵入式 Python 性能采样工具,Rust 编写、开销极低(<0.1%),无需改代码或重启程序即可定位性能瓶颈。
py-spy 入门与实战
安装
支持 Windows、Mac、Linux:
pip install py-spy # 推荐
brew install py-spy # Mac
sudo apt install py-spy # Linux验证:py-spy --version,核心命令:top、record、dump。
核心命令
top:实时 CPU 占用
实时监控函数 CPU 占用,快速定位最耗时函数。
sudo py-spy top --pid 12345 # 分析运行进程
py-spy top -- python test.py # 分析脚本运行后按数字 1-4 排序(1:自身耗时占比;2:总耗时占比;3:自身总时间;4:总时间)。
Linux/Mac 需 sudo(CAP_SYS_PTRACE 权限)。
record:生成火焰图
采样函数调用,生成 SVG 火焰图,直观显示调用关系和耗时。
sudo py-spy record -o profile.svg --pid 12345
py-spy record -o profile.svg -- python test.py采样后按 Ctrl+C 停止,浏览器打开 profile.svg。
火焰图解读:
- Y 轴:调用栈(上层被调用,下层调用者)
- X 轴:采样时间
- 横条越长,耗时越多
- “平顶”函数是主要瓶颈
可选参数:
--rate 50:采样频率(默认 100Hz)--duration 60:采样时长
dump:查看当前调用栈
即时打印所有线程调用栈,排查程序卡死、无响应问题。
sudo py-spy dump --pid 12345实战案例
场景:数据加载缓慢
步骤 1:获取 PID
python test_dataset.py &
# 返回 PID,如 116079测试脚本:
import time
import numpy as np
class DatasetGenerator:
def __getitem__(self, item):
self.do_something()
return (np.array((item)),)
def do_something(self):
cnt = 0
for i in range(100000000): # 一亿次循环
cnt += 1
def __len__(self):
return 50
def test_generator():
data = DatasetGenerator()
start = time.time()
for item in range(len(data)):
data[item]
print("耗时:", time.time() - start)
start = time.time()
if __name__ == "__main__":
test_generator()步骤 2:定位瓶颈
sudo py-spy top --pid 116079
# 发现 do_something 占用 100% CPU步骤 3:生成火焰图
sudo py-spy record -o dataset_profile.svg --pid 116079火焰图显示 do_something 横条最长,确认瓶颈。
步骤 4:优化验证
删除一亿次循环后,耗时从 5 秒/条降至 0.001 秒/条。
top 和 record 结果示例
示例代码:
Transclude of learn-py-spy.zip
单进程 CPU 密集型:

引入 IO 等待:

多进程场景(观察 GIL 的变化):

注意事项
- 权限:Linux/Mac 需 sudo,Windows 需管理员权限
- 不支持:PyPy、Jython、嵌入式 Python、C 扩展内部
- 线上使用:默认 100Hz 开销极低,可用
--rate 50降频 - 容器:Docker 加
--cap-add SYS_PTRACE,Kubernetes 配 securityContext
总结
| 场景 | 命令 |
|---|---|
| 本地调试 | py-spy top/record -- python 脚本 |
| 线上排查 | py-spy top/record --pid 进程号 |
| 程序卡死 | py-spy dump --pid 进程号 |
py-spy 无侵入、上手快,3 个命令覆盖 80% 性能问题。