orjson 与 json:实战对比与选型指南(含示例)
结论先行
- 性能:orjson 在序列化、反序列化上通常显著快于标准库 json,适合高吞吐/低延迟场景。
- 易用性与依赖:json 零依赖、API 熟悉,默认选择依旧"够用",部署更简单。
- 特性 :orjson 原生支持
dataclass
、datetime
、numpy
、UUID
等类型,且严格 UTF-8 与 RFC 8259;但dumps()
返回bytes
,缩进只支持 2 空格,部分行为需通过选项切换。
基本差异一览
-
返回类型
- json :
json.dumps(obj)
返回str
- orjson :
orjson.dumps(obj)
返回bytes
(UTF-8)。若你需要字符串,可orjson.dumps(obj).decode("utf-8")
- json :
-
性能(示意)
- 多项对比中,orjson 在
dumps
/loads
上均为领先者,常见场景可比标准库快数倍。 - 参考:
- orjson README 的性能说明("something like 10x as fast as json" 取决于数据与环境)
- 社区基准示例:在 3M 次循环里,orjson 明显快于 json 与 ujson(见文末参考)
- 多项对比中,orjson 在
-
编码与规范
- orjson :严格 UTF-8 与 RFC 8259。输出始终为 UTF-8 字节序列,不支持将非 ASCII 字符转义为
\uXXXX
。 - json :默认
ensure_ascii=True
,会把中文等非 ASCII 字符转成转义序列;若想直出 UTF-8,应ensure_ascii=False
。
- orjson :严格 UTF-8 与 RFC 8259。输出始终为 UTF-8 字节序列,不支持将非 ASCII 字符转义为
-
类型支持
- orjson :原生序列化
dataclasses.dataclass
、datetime
/date
/time
、uuid.UUID
、numpy.ndarray
等;也支持enum
、TypedDict
等。 - json :遇到上述对象通常需要自定义
default
处理或手动转换。
- orjson :原生序列化
-
字典键(非字符串)
- json :默认允许键是
str
、int
、float
、bool
或None
(序列化时会转为字符串)。 - orjson :默认仅允许
str
键;如需其它类型,需加option=orjson.OPT_NON_STR_KEYS
。
- json :默认允许键是
-
整数与浮点
- orjson :整数默认限制在 64 位;若开启
OPT_STRICT_INTEGER
,限制为 53 位(与 JS Number 安全整数范围一致)。 - json :对大整数更宽松(Python
int
任意精度),但落地到 JS/数据库时仍需考虑精度问题。
- orjson :整数默认限制在 64 位;若开启
-
Pretty Print(美化输出)
- json :
indent=N
任意缩进选择,sort_keys=True
排序。 - orjson :仅提供
OPT_INDENT_2
(固定 2 空格);排序使用OPT_SORT_KEYS
。
- json :
-
运行时/平台支持
- orjson:需额外依赖,提供多平台 wheel;不支持 PyPy。某些极简/受限环境可能安装困难。
- json:标准库,处处可用。
示例 1:中文输出对比(避免"乱码/转义")
python
# 标准库 json:默认 ensure_ascii=True,会输出 \uXXXX 转义
import json
data = {"msg": "你好,世界"}
print(json.dumps(data))
# 输出: {"msg": "\u4f60\u597d\uff0c\u4e16\u754c"}
# 正确直出 UTF-8(推荐)
print(json.dumps(data, ensure_ascii=False))
# 输出: {"msg": "你好,世界"}
# orjson:始终输出 UTF-8 bytes,不会转义为 ASCII
import orjson
print(orjson.dumps(data))
# 输出: b'{"msg":"你好,世界"}'
print(orjson.dumps(data).decode("utf-8"))
# 输出: {"msg": "你好,世界"}
要点:
- Web 框架(如 FastAPI/Starlette)若使用
ORJSONResponse
,会直接写 bytes,浏览器看到的就是 UTF-8。 - 若走标准
JSONResponse
,用json.dumps(..., ensure_ascii=False)
也可确保中文直出。
示例 2:datetime 与 numpy 的零样板序列化
python
import datetime as dt
import numpy as np
import orjson
obj = {
"ts": dt.datetime(1970, 1, 1),
"arr": np.array([[1, 2], [3, 4]]),
}
# 时区与 numpy 处理通过选项开启
payload = orjson.dumps(
obj,
option=orjson.OPT_NAIVE_UTC | orjson.OPT_SERIALIZE_NUMPY,
)
print(payload)
# b'{"ts":"1970-01-01T00:00:00+00:00","arr":[[1,2],[3,4]]}'
若用标准库 json,上述对象需要手工把 datetime 转字符串、把 ndarray 转 list。
示例 3:FastAPI 集成
python
# pip install fastapi uvicorn orjson
from fastapi import FastAPI
from fastapi.responses import ORJSONResponse, JSONResponse
app = FastAPI()
@app.get("/orjson", response_class=ORJSONResponse)
async def use_orjson():
return {"msg": "你好,世界", "nums": [1, 2, 3]}
@app.get("/json", response_class=JSONResponse)
async def use_json():
# 若返回中文,建议 ensure_ascii=False(可由 JSONResponse 控制或自定义)
return {"msg": "你好,世界", "nums": [1, 2, 3]}
# 也可以全局:FastAPI(default_response_class=ORJSONResponse)
提示:使用 ORJSONResponse
需要安装 orjson
,否则会出现类似 "orjson must be installed to use ORJSONResponse" 的断言错误。
示例 4:微基准(仅作方向性参考)
python
import time, json, orjson
m = {"a": 1, "b": [1, 2, 3], "msg": "你好"}
def bench(name, dumps, loads, loops=300_000):
t0 = time.time()
for _ in range(loops):
s = dumps(m)
loads(s)
print(name, time.time() - t0)
bench("json", json.dumps, json.loads)
bench("orjson", lambda x: orjson.dumps(x), orjson.loads)
# 在多篇社区对比中,orjson 通常显著快于 json(机器/数据不同,结果会有差异)。
适用场景建议
-
选 orjson:
- 性能关键:高 QPS、低延迟接口;大型 JSON 读写;频繁序列化复杂对象
- 类型友好 :项目中大量使用
dataclass
、datetime
、numpy
、UUID
等 - 一致编码:严格 UTF-8/RFC 8259 要求
-
选 json:
- 零依赖与可移植性:对环境极简、对部署体积敏感
- 团队熟悉度:通用 API、学习成本低
- PyPy/特殊运行时:orjson 不支持的场景
迁移与最佳实践
-
明确
bytes
与str
的差异:orjson 的dumps
返回bytes
;框架若可直接写 bytes,则无需再解码。 -
中文/多语言输出:
- orjson 默认 UTF-8,无需额外参数;
- 标准库要
ensure_ascii=False
才能直出 UTF-8。
-
Pretty/排序:
- json:
indent
任意、sort_keys=True
; - orjson:
OPT_INDENT_2
、OPT_SORT_KEYS
。
- json:
-
字典非字符串键:
- orjson 需
OPT_NON_STR_KEYS
;注意潜在"重复键"风险(不同类型序列化后变为相同字符串)。
- orjson 需
-
日期时间:
- orjson 若需将 naive datetime 视为 UTC,使用
OPT_NAIVE_UTC
; - 若需自定义输出,可用
OPT_PASSTHROUGH_DATETIME
+default
。
- orjson 若需将 naive datetime 视为 UTC,使用
-
大整数/精度:
- orjson 默认 64 位,或用
OPT_STRICT_INTEGER
限制 53 位; - 标准库虽更宽松,但传至 JS/DB 时仍需关注精度丢失。
- orjson 默认 64 位,或用
参考
- orjson 官方文档与 README(功能/选项/性能说明)
- GitHub 仓库:ijl/orjson
- 基准文章(举例,方向性参考,结果随机器/数据不同而变)
- Benchmarking Python JSON serializers(json/ujson/orjson 对比)
- 文中示例:orjson 明显快于 json 与 ujson
- 链接:dollardhingra.com 的对比文
- Finding the fastest Python JSON library(更广泛的库与多 Python 版本对比)
- Benchmarking Python JSON serializers(json/ujson/orjson 对比)