orjsonが必要になる瞬間
🧭 はじめに(What / Why)
このページで理解できることは次の3点です。
- orjsonは「jsonの高速版」ではなく、JSON境界のコストを現実的に削るための専用部品であること
- orjsonが必要になるのは、速度以前に回数と位置の問題であること
- orjsonを入れるかどうかは「体感の遅さ」ではなく「構造的な負荷」で判断すべきこと
orjsonは内部表現を速くする道具ではない。境界(serialize / deserialize)を短くする道具。
🧱 立ち位置の整理(Before / After)
✅ 何と置き換わる存在か
-
Before
- 標準ライブラリの
json.dumps/json.loads
- 標準ライブラリの
-
After
- orjson の
orjson.dumps/orjson.loads
- orjson の
😩 それがなぜ辛かったか
-
JSONは「軽そう」に見えるが、実際には
- 文字列化
- 型判定
- エスケープ
- Unicode処理 の集合体で、CPUを確実に食う
-
API・ログ・キャッシュなど、回数が増えると一気にボトルネック化する
-
json標準は
- 遅い(特に dumps)
- オプション指定が分散している
- datetime 等の実用型に弱い
🎯 解決したかった本質
- 「JSON境界は無料ではない」 という現実を直視し
- そこを実装ではなく部品で殴りたい
🧠 設計思想の核(最重要)
優先したもの
-
圧倒的な速度
- Python製ではなく Rust 製
- GILを極力掴まない設計
-
実用型への寄り添い
datetimeUUIDdataclassを素で扱える
-
オプションの明示性
OPT_NAIVE_UTCOPT_SORT_KEYSOPT_NON_STR_KEYSなど
orjsonは「JSONを安全に、速く、現実的に使う」という一点に設計を全振りしている。
捨てたもの
- 純Python実装(=環境依存が増える)
- 柔軟なカスタマイズ(default関数文化を捨てている)
- 学習コストの低さ(APIはjson標準と微妙に違う)
✅❌ できること / できないこと
✅ できること(得意)
- JSONの高速な serialize / deserialize
- 実用型(datetime / dataclass)の自然な扱い
- 大量データ・高頻度APIでのCPU負荷削減
- pydantic等との組み合わせによる境界高速化
❌ できないこと(期待してはいけない)
- JSON以外の形式(YAML / MessagePack 等)
- 小規模・低頻度処理での「分かりやすい速さ」
- 環境差ゼロの配布(ビルド済みwheel依存)
CLIツールや一回きりのバッチでorjsonを入れても、体感差はほぼ出ない。
🧪 典型的な利用パターン(最小)
JSON境界での差し替え
import orjson
data = {"x": 1, "y": 2}
raw = orjson.dumps(data)
obj = orjson.loads(raw)
strではなくbytesを返す点が重要- Webフレームワーク・レスポンス層ではむしろ都合が良い
APIレスポンス生成・ログ出力・キャッシュ保存など、「回数が多い境界」で差し替えると効果が出やすい。
🧯 よくある誤解・アンチパターン
1) 「とりあえず速そうだから入れる」
- jsonがボトルネックかどうか測っていない
- 設計が悪いのに、部品で誤魔化している可能性
orjson導入前に「JSON変換が何回走っているか」を数えた方がいい。
2) 内部処理を全部orjson前提にする
- bytes / str の境界が曖昧になりやすい
- 内部表現まで「JSONっぽく」なり、設計が汚れる
3) default関数文化の持ち込み
- orjsonは「何でも変換する」思想ではない
- 対応していない型は明示的にエラーにする方針
orjsonに無理やり万能serializerの役割を持たせると、設計の責任分界が崩壊する。
🔗 他ライブラリとの関係
- json(標準): 低頻度・可搬性重視なら今でも十分
- pydantic: v2以降はorjson前提での高速境界処理が自然
- FastAPI / Starlette: レスポンス生成でorjsonを使うとCPU使用率が下がるケースが多い
orjsonは単独で使うより、「境界レイヤの下請け」として組み込むと価値が最大化する。
🧾 まとめ(1文で言うと)
orjsonは「jsonの代替」ではなく、JSON境界がボトルネックになった瞬間に投入するための高性能専用部品である。