為什麼 orjson 幾乎是現代 Python Web 專案的預設選擇?
在 Python 生態中,JSON 幾乎無所不在:
API 回傳、設定檔、Log、Streaming、Cache、Message Queue……
問題從來不是「要不要用 JSON」,而是:
用哪一個 JSON library,才能在效能與開發體驗之間取得最佳平衡?
如果你還在 json、ujson、orjson 之間猶豫,這篇文章會給你一個非常明確的答案。
TL;DR(結論先行)
- 新專案、Web API、Streaming:👉 選
orjson - 維護舊專案、想無痛加速:👉 選
ujson - 小腳本、零依賴需求:👉 用標準庫
json
如果你在用 FastAPI / Starlette / SSE / NDJSON,
那幾乎沒有理由不用 orjson。
一、為什麼效能突然變得這麼重要?
在現代 Web 架構中,JSON 序列化早就不是「可以忽略的成本」:
- 高併發 API:每秒序列化上千次
- Streaming / SSE:每個 chunk 都要
dumps - LLM 應用:token 一個一個吐,序列化是熱路徑(hot path)
慢 0.1ms,看起來很小,但乘以 10,000 次就是真實延遲。
二、三大 JSON Library 的核心差異
整體比較表
| 特性 | orjson | ujson | 標準 json |
|---|---|---|---|
| 底層實作 | Rust | C/C++ | Python + C |
| dumps 回傳 | bytes | str | str |
| 序列化速度 | 最快 | 快 | 慢 |
| datetime 支援 | 原生支援 | ❌ | ❌ |
| dataclass 支援 | 原生支援 | ❌ | ❌ |
| JSON 規範 | 嚴格 | 較寬鬆 | 嚴格 |
一句話總結:
orjson是「效能極限 + 現代 Python 類型友善」的 JSON。
三、orjson 為什麼這麼快?
1️⃣ Rust 的優勢
- 記憶體安全
- 更 aggressive 的最佳化
- 減少 Python / C 邊界切換成本
2️⃣ 關鍵差異:bytes vs str
這是效能差距的核心。
orjson.dumps(data) # -> bytes
json.dumps(data) # -> str
在 Web Server 中,流程通常是:
Python Object
→ JSON String
→ UTF-8 encode
→ Bytes
→ Socket
orjson 直接跳過中間那個 String。
FastAPI 為什麼預設推薦 orjson?
因為 HTTP Response 最終就是 bytes。
四、開發體驗:orjson 幾乎不用寫樣板程式碼
datetime、dataclass,直接可用
import orjson
from datetime import datetime
from dataclasses import dataclass
@dataclass
class User:
id: int
name: str
data = {
"created_at": datetime.now(),
"user": User(1, "Alice")
}
print(orjson.dumps(data))
👉 不用 Custom Encoder,不用轉型,不用 try/except
這一點在真實專案中,能省下大量心智負擔。
五、Web API:前端完全不用改
這是很多人第一次聽到 orjson 時最大的疑問:
前端是不是也要裝東西?
答案是:完全不用。
orjson 只是「產生 JSON 的方式不同」,
產物仍然是 100% 標準 JSON。
// React / Next.js
const res = await fetch("/api/user");
const data = await res.json(); // 完全一樣
前端甚至不知道後端換過 JSON library。
六、Streaming / SSE:orjson 的主戰場
在 Streaming 場景中,orjson 的優勢會被放大。
SSE 範例(FastAPI)
import orjson
import asyncio
from fastapi.responses import StreamingResponse
async def event_generator():
for i in range(5):
payload = {"token": i, "text": "thinking..."}
yield b"data: " + orjson.dumps(payload) + b"\n\n"
await asyncio.sleep(0.5)
@app.get("/stream")
def stream():
return StreamingResponse(event_generator(), media_type="text/event-stream")
為什麼這樣寫很重要?
- 全程
bytes,沒有 decode / encode - 每個 chunk 都是最小成本
- 非常適合 LLM token streaming
七、那 MessagePack 呢?不是更快嗎?
是的,但要看 「誰是資料消費者」。
決策矩陣
| 使用場景 | 推薦 |
|---|---|
| 瀏覽器 / Web API | orjson |
| Backend-to-Backend | MessagePack |
| Redis / Cache | MessagePack |
| Log / Observability | orjson |
| 小腳本 | 標準 json |
MessagePack 贏在體積與頻寬,
orjson 贏在 通用性 + 開發效率 + 生態整合。
八、唯一要注意的陷阱:BigInt
這不是 orjson 的問題,是 JSON 的天生限制。
{"id": 9223372036854775807}
JavaScript 可能會精度遺失。
👉 解法很簡單:後端轉成字串再送。
九、總結:什麼時候「不該」用 orjson?
只有三種情況:
- 極簡腳本(不想 pip install)
- 非常舊的 Python 版本
- 專案嚴格禁止 native extension
否則:
在 2025 年的 Python Web 專案中,不用
orjson,反而需要理由。
結語
orjson 的成功,不是因為它「比較快一點」,
而是因為它 剛好踩在現代 Python 的所有甜蜜點上:
- 高效能
- 類型友善
- Web 原生
- Streaming 友好
- 前端零成本
如果你正在做 API、SSE、LLM 應用或任何高頻 JSON 處理,
把 orjson 當成預設選項,你幾乎不會後悔。