## Python orjson:一个顺手的高速 JSON 解析库
刚接触Python那会儿,处理JSON基本上就是json模块一条路走到黑。后来项目规模上来了,数据量一涨,json.loads和json.dumps那点性能瓶颈就藏不住了。有人开始用simplejson,有人用ujson,不过最近几年,越来越多的生产环境里出现了orjson的身影。
这东西其实是个用Rust写的JSON库,核心逻辑用Rust实现,通过Python的C扩展接口暴露给上层调用。为什么选Rust?因为它能在保证内存安全的前提下,把JSON解析和序列化的速度推到极致。简单说,orjson就是个更快、更省内存的JSON处理工具,而且数据越复杂,优势越明显。
它到底能干什么
日常用的JSON操作,orjson都覆盖了。解析字符串、序列化对象,这些基础能力跟标准json模块别无二致。但有几个地方确实让json模块望尘莫及:
第一,处理大JSON文件时,orjson的按需解析是个好东西。有时候我们只需要响应体里那一小段数据,orjson可以选择性地解析特定字段,而不是把整个JSON结构全塞进内存。这就好比翻一本厚厚的黄页,你是想一页一页全看完,还是只查那个具体的电话号码?
第二,对日期时间的原生支持。标准库里的json模块碰到datetime对象直接抛TypeError,得自己写encoder。orjson倒好,它能直接把datetime序列化成ISO 8601格式的字符串。这个特性在写API接口的时候特别省心。
第三,bytes类型的序列化。Python的json模块对bytes是束手无策的,但orjson能把它序列化成UTF-8编码的字符串。如果你的应用里经常跟二进制数据打交道,这个细节能省掉不少编码解码的麻烦事。
怎么用起来
安装很简单,pip install orjson就行。用法也基本是照着json模块的API风格来的,上手几乎没有学习成本:
importorjson# 解析JSON字符串data='{"name": "张三", "age": 30}'parsed=orjson.loads(data)# 序列化成JSON字符串output=orjson.dumps({"name":"李四","age":25})# 注意这里返回的是bytes类型,不是strprint(output)# b'{"name":"李四","age":25}'有个小细节需要注意:orjson.dumps默认返回bytes,而不是str。要想拿到字符串,可以这样:
result=orjson.dumps(obj).decode('utf-8')其实这就是个设计哲学问题。orjson的作者认为JSON数据在网络传输和文件存储中本就是UTF-8的形式,bytes才是最原始的表示。如果你写web应用,bytes直接给响应体比str转bytes更快。
处理可选参数的时候,orjson用option常量来控制行为,而不是像json模块那样靠一个个bool参数堆:
data={"name":"赵六","created_at":datetime.now()}# 序列化datetime对象output=orjson.dumps(data,option=orjson.OPT_OMIT_MICROSECONDS|orjson.OPT_UTC_Z)# 排序键名output=orjson.dumps(data,option=orjson.OPT_SORT_KEYS)这个option的设计值得玩味。用位运算的方式组合多个选项,虽然一开始看着不习惯,但用久了发现比给函数传一堆命名参数要灵活,特别是组合选项的时候。
怎么用好它
不是所有场景都需要上orjson。如果你的应用每次只处理几个KB的小JSON,拿json模块对付一下也差不了多少。但一旦遇到高频率、大数据的JSON操作,orjson的优势就淋漓尽致了。
举个实在的例子:一个日志收集系统,每天要处理上亿条JSON格式的日志条目。这个时候哪怕每条记录省下零点几毫秒,累积下来的性能提升都是可观的。而且orjson往往能省出30%到50%的CPU开销,这个在生产环境里可能意味着少用几台服务器。
一个老生常谈但依然要提的:别在性能瓶颈出现之前盲目优化。先把代码写清楚,跑对了,然后用性能分析工具定位真正的瓶颈在哪里。如果发现JSON解析占了很大比重,再用orjson替换也不迟。这个替换成本很低,基本上改一行import就行。
处理敏感信息的时候要注意,orjson默认会把非ASCII字符做转义。如果接口需要返回中文,却看到一堆转义字符,那就需要关闭OPT_ESC_FORWARD_SLASH或者自定义encoder。其实这个转义行为是JSON规范里允许的,但有些前端框架或者下游服务不一定认这个。
和同类技术掰掰手腕
标准库的json模块自然不必多说,纯Python实现,没什么性能可言。但它胜在最稳定、最兼容,是调试阶段的好伙伴。
simplejson其实跟json模块一脉相承,算是对标准库的补充。它支持更多JSON规范里的细节,比如无限递归检测、自定义对象的serialization。不过性能上,simplejson跟orjson比还是有差距的,大概是两倍不到的差距。
ujson(UltraJSON)也算是个老牌选手了。它用C语言实现,速度比json模块快不少。但有一个致命的短板:它对数据的严格性要求比较低,有时候会悄无声息地吞掉一些问题数据。比如一个非法的UTF-8字符,ujson可能就默默处理了,orjson会直接抛异常。这个取舍让orjson在生产环境里更有竞争力。
还有一个叫python-rapidjson的库,底层用的是RapidJSON这个C++库。性能也算不错,不过跟orjson比起来,在处理重复字段、多个空格这类边缘情况时,orjson表现得更加谨慎和可靠。
说到底,orjson胜在两点:速度快,而且快得稳定;数据类型支持完善,能省掉很多手动转换的麻烦。如果非要说缺点,大概就是它对JSON的严格程度比较高,碰到不符合规范的数据就不客气地抛异常,这在处理不可控的外部数据源时需要注意。
不过话说回来,对数据的严格检查本身也是好事。与其让问题数据悄无声息地通过,不如尽早发现并处理。