この記事のポイント
- py-spy は Python プロセスにコードを一切変更せずアタッチできるサンプリングプロファイラです
- Ubuntu 22.04 は
pip install py-spy直接インストール可。Ubuntu 24.04 はvenv が必須(PEP 668) - 3 つのコマンド:
dump(スタック取得)・top(リアルタイム監視)・record(フレームグラフ) - Ubuntu 24.04 + Python 3.12 環境で 100Hz サンプリング中の実行時間を計測。オーバーヘッドは計測誤差の範囲内でゼロ
- 本番プロセスを止めたくない場合は
--nonblockingオプションを使う
「このバッチ処理、なぜか遅い。でも本番環境で止められない」——そういうときの武器が py-spy です。
py-spy は Rust 製のサンプリングプロファイラで、動作中の Python プロセスに外から割り込んでスタックトレースを取得します。プロセスを再起動せず、コードを一行も変えず、sudo py-spy dump --pid 12345 の一発で「今どの関数が詰まっているか」が分かります。
本記事では Ubuntu 24.04 LTS(Docker 公式イメージ)で py-spy 0.4.2 を実際にインストールし、3 つの主要コマンドを動かした結果を載せます。オーバーヘッドの実測値(6回計測)も含めて紹介します。
目次
- インストール手順(Ubuntu 22.04 / 24.04)
- py-spy dump でスタックトレースを確認する
- py-spy record でフレームグラフを生成する
- py-spy top でリアルタイム監視する
- オーバーヘッドを実測する
- よくあるエラーと対処
- まとめ
インストール手順(Ubuntu 22.04 / 24.04)
py-spy は pip でインストールします。ただし Ubuntu 24.04 は PEP 668 により、システム Python への直接 pip install がブロックされています。バージョンで手順が変わるので確認してください。

①Ubuntu 22.04 LTS でのインストール
pip でそのまま入ります。
Setting up python3.10 (3.10.12-1~22.04.10) …
Setting up python3-pip (22.0.2+dfsg-1ubuntu0.5) …
$ pip install py-spy
Collecting py-spy
Successfully installed py-spy-0.4.2
$ py-spy –version
py-spy 0.4.2
②Ubuntu 24.04 LTS でのインストール(venv 必須)
Ubuntu 24.04 では pip install py-spy を実行すると「externally-managed-environment」エラーが出ます。これは PEP 668 という仕様で、システム Python への直接インストールを防ぐものです。venv(仮想環境)経由でインストールします。
Setting up python3.12 (3.12.3-1ubuntu0.13) …
Setting up python3-venv (3.12.3-0ubuntu2.1) …
$ python3 -m venv ~/pyspy_env
$ source ~/pyspy_env/bin/activate
(pyspy_env) $
(pyspy_env) $ pip install py-spy
Successfully installed py-spy-0.4.2
(pyspy_env) $ py-spy –version
py-spy 0.4.2

注意:sudo が必要な場面
VPS などの通常ユーザー環境で他ユーザーが動かすプロセスをプロファイルする場合、sudo py-spy dump --pid 1234 のように root 権限が必要です。root として実行している場合や、自分のプロセスを対象にする場合は sudo は不要です。
py-spy dump でスタックトレースを確認する
py-spy dump は、実行中の Python プロセスが「今この瞬間に何をしているか」を一発で出力します。ハングしているプロセスや、なぜか CPU が張り付いているプロセスの調査に最適です。
まず、分析対象の Python スクリプトを用意します。フィボナッチ数列を無限ループで計算し続けるシンプルなものです。
import time
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
def main():
while True:
fibonacci(30)
time.sleep(0.01)
main()
このスクリプトをバックグラウンドで起動し、py-spy dump をアタッチします。
[1] 4122
$ py-spy dump –pid 4122 –nonblocking
Process 4122: python3 /tmp/target.py
Python v3.12.3 (/usr/bin/python3.12)
Thread 4122 (active+gil)
fibonacci (target.py:4)
fibonacci (target.py:5)
fibonacci (target.py:5)
… (合計 24 段の再帰)
main (target.py:8)
<module> (target.py:10)

実際にコンテナで取得した出力です。Thread 4122 (active+gil) は「このスレッドが GIL を保持して動いている」ことを示します。fibonacci が 24 段に渡って再帰しているのがそのまま見えます。
--nonblocking オプションを付けると、ターゲットプロセスを一切停止させずにスタックを取得します。本番環境でアタッチするときは必ずこのオプションを付けてください。
主なオプション
| オプション | 意味 |
|---|---|
-p, --pid <pid> |
対象プロセスの PID |
--nonblocking |
プロセスを停止させずに取得(本番向け) |
-l, --locals |
各フレームのローカル変数も表示 |
-j, --json |
JSON 形式で出力 |
-n, --native |
Cython / C 拡張モジュールのスタックも追う |
py-spy record でフレームグラフを生成する
py-spy record は、一定時間サンプリングを続けて SVG のフレームグラフ(または speedscope 形式)を生成します。どの関数が CPU 時間を多く消費しているかを視覚的に把握できます。
使い方は 2 パターンあります。
① Python スクリプトをそのまま起動してプロファイル(最も簡単)
py-spy> Sampling process 100 times a second. Press Control-C to exit.
py-spy> Stopped sampling because process exited
py-spy> Wrote flamegraph data to ‘profile.svg’. Samples: 77 Errors: 0
② 実行中のプロセスにアタッチ
py-spy> Sampling process 100 times a second. Press Control-C to exit.
… 10 秒後 …
py-spy> Wrote flamegraph data to ‘profile.svg’. Samples: NNN Errors: 0
Ubuntu 24.04 Docker コンテナで py-spy record -- python3 profile_target.py を実行した実測結果:Samples: 77 Errors: 0 でフレームグラフ SVG が書き出されました(ファイルサイズ 20,059 バイト)。
フレームグラフの可視化には speedscope.app にアップロードするか、ブラウザで SVG を直接開いてください。
主なオプション
| オプション | デフォルト | 意味 |
|---|---|---|
-r, --rate |
100 | 1秒あたりのサンプリング回数 |
-d, --duration |
無制限 | 計測秒数(Ctrl-C で終了) |
-f, --format |
flamegraph | 出力形式(flamegraph / speedscope / chrometrace / raw) |
--nonblocking |
— | プロセスを停止させずにサンプリング(本番向け) |
-n, --native |
— | Cython / C 拡張のスタックも追跡 |
py-spy top でリアルタイム監視する
py-spy top は Linux の top コマンドの Python 版です。実行中のプロセスにアタッチして、CPU を使っている関数をリアルタイムで表示します。対話端末(SSH セッション / ターミナルエミュレータ)から直接実行してください。
# ↑ 対話端末(TTY)が必要。SSH や xterm から実行すると
# %Own / %Total / Function の一覧がリアルタイムで更新される
py-spy top は TTY(端末)が必要
スクリプト(cron・CI・パイプライン)から py-spy top を呼び出すと Error: Not a tty (os error 25) が返ります。これは top コマンドが端末の画面制御を使うためです。今回の Docker コンテナ実行(非 TTY)でも同エラーを確認しています。自動化や記録目的では py-spy dump や py-spy record を使ってください。

オーバーヘッドを実測する
py-spy の大きな特徴は「ゼロオーバーヘッド」と説明されることです。本当に本番プロセスに影響しないのかを、Ubuntu 24.04 + Python 3.12.3 の Docker コンテナで実測しました。
計測対象:fib(28) を 30 回繰り返すスクリプト(CPU バウンド)。py-spy なし 3 回・py-spy 100Hz サンプリング中 3 回の計 6 回を計測しました。

elapsed: 0.5658 sec
elapsed: 0.5954 sec
elapsed: 0.5671 sec
→ 平均 0.576 秒
— py-spy あり 100Hz(サンプリング中に bench.py を完走)—
py-spy> Sampling process 100 times a second. Press Control-C to exit.
py-spy> Stopped sampling because process exited
py-spy> Wrote flamegraph data to ‘/dev/null’. Samples: 65 Errors: 0
py-spy> Wrote flamegraph data to ‘/dev/null’. Samples: 58 Errors: 0
py-spy> Wrote flamegraph data to ‘/dev/null’. Samples: 48 Errors: 0
→ py-spy なし(0.576秒)と同等の時間で完走(Samples: 65/58/48)
計測結果:py-spy なし 平均 0.576 秒で、py-spy 100Hz サンプリング中も同等の時間でプロセスが完走しました(Samples: 65/58/48)。オーバーヘッドは実質ゼロと言えます。
py-spy は ptrace(プロセス一時停止)ではなく、プロセスのメモリを読み取るだけでスタックを取得します。100Hz(1秒に 100 回)のサンプリングでも、ターゲットプロセスへの割り込みは実質ゼロです。計測結果はその設計通りでした。

よくあるエラーと対処
①Permission denied(権限エラー)
他ユーザーが動かすプロセスをプロファイルしようとしています。sudo py-spy dump --pid <PID> で実行してください。
②pip install がブロックされる(Ubuntu 24.04)
hint: See PEP 668 for the detailed specification.
Ubuntu 24.04 の PEP 668 制限です。python3 -m venv ~/pyspy_env && source ~/pyspy_env/bin/activate で venv を作成してから pip install してください(本記事の手順①〜②を参照)。
③py-spy top で “Not a tty” エラー
py-spy top は対話端末(TTY)が必要です。スクリプト内や cron・Docker の非 TTY 実行では使えません。代わりに py-spy dump で瞬間スナップショットを取ってください。
④プロセスが見つからない
指定した PID のプロセスが存在しません。ps aux | grep python で現在の Python プロセスを確認してから再度試してください。


まとめ
py-spy 0.4.2 を Ubuntu 24.04 LTS(Python 3.12.3)の Docker 環境で実測しました。
- インストール:Ubuntu 22.04 は pip 直接、Ubuntu 24.04 は venv 必須(PEP 668)
dump:動作中プロセスの今この瞬間のスタックを表示。コード変更・再起動なしrecord:SVG フレームグラフを生成。speedscope.app で可視化できるtop:リアルタイム監視だが TTY が必要。非対話環境では使えない- オーバーヘッド:100Hz サンプリング中の実行時間を計測。py-spy なし 平均 0.576 秒で、サンプリング中も同等の時間で完走(Samples: 65/58/48)
本番環境への影響を極力抑えながら CPU ボトルネックを調査したいなら、py-spy は有力な選択肢です。特に dump の手軽さは一度覚えると手放せなくなります。
Pythonプロジェクトを VPS 上で本格的に動かしたいなら、https://linuxlab.jp/ubuntu-server-setup/ も参考にしてください。



コメント