Python 的 orjson 库
5 分钟阅读
#Python
#orjson
Python 的 orjson 库
我们来详细探讨一下 orjson 库以及为什么它通常比 Python 标准库中的 json 模块性能更好。
首先,需要澄清一点:orjson 并不是 Python 3.11 或任何 Python 版本的标准库组成部分。 它是一个非常流行的、高性能的第三方 Python 库,需要单独安装(通常通过 pip install orjson)。Python 标准库中用于处理 JSON 的模块仍然是 json。
尽管如此,orjson 因其出色的性能而广受青睐,尤其是在需要高速处理大量 JSON 数据的场景中。它之所以更快,主要得益于以下几个关键因素:
底层实现语言 (Rust)
orjson的核心部分是使用 Rust 语言编写的。Rust 是一种现代的、内存安全的系统编程语言,以其接近 C/C++ 的高性能而闻名。- 相比之下,Python 标准库的 
json模块主要是用 Python 编写的,虽然它也包含一个 C 语言编写的加速器 (_json),但在许多操作上,专门为性能优化的 Rust 代码通常能实现更高的执行效率。Rust 的编译时优化、对内存布局的精细控制以及避免 Python 解释器开销的能力,都对性能提升有显著贡献。 
优化的序列化和反序列化算法
orjson在将 Python 对象序列化为 JSON 字符串 (dumps) 和将 JSON 字符串反序列化为 Python 对象 (loads) 的过程中,采用了高度优化的算法。- 它可能利用了更快的字符串处理技术、更高效的内存管理策略,并可能针对现代 CPU 架构(如 SIMD 指令)进行了优化,以加速解析和生成过程。
 
原生支持更多数据类型
- 标准 
json库仅原生支持基本的 Python 类型(如dict,list,str,int,float,bool,None)。对于其他类型(如datetime,uuid,bytes,dataclasses,enums等),你需要提供自定义的default函数(用于序列化)或object_hook(用于反序列化)。这些自定义函数的调用会增加额外的开销。 orjson内置了对多种常用但非 JSON 原生支持的 Python 类型的快速序列化支持,包括datetime.datetime,uuid.UUID,int(任意大小),float(包括NaN,Infinity,-Infinity),str(正确处理 UTF-8),bytes,bytearray,memoryview,dataclasses,enums,decimal.Decimal等。这种原生支持避免了 Python 层面的回调开销,直接在 Rust 代码中高效处理,从而显著提高了涉及这些类型的 JSON 操作速度。
严格遵循 JSON 规范 (RFC 8259)
orjson严格遵守 JSON 规范。这意味着它在解析时可能比标准库更严格,不会接受一些格式略有问题的 JSON。虽然这在某些情况下可能需要你确保输入是完全标准的 JSON,但这种严格性也意味着它可以进行更直接、更少分支判断的解析,有助于提高速度。- 它保证输出的 JSON 是符合 RFC 8259 规范的有效 UTF-8 编码字符串。
 
专注于性能和正确性
orjson的设计目标就是提供一个既正确又快速的 JSON 库。它在实现上可能做出了一些有利于性能的权衡(例如,可能不如标准库那样灵活地处理某些边缘情况或非标准格式),并将性能优化置于非常高的优先级。
总结
总的来说,orjson 的高性能主要来源于:
- 使用 Rust 编写核心逻辑,利用了编译语言的性能优势和内存效率。
 - 采用高度优化的序列化/反序列化算法。
 - 内置对多种 Python 类型的原生快速支持,减少了 Python 回调开销。
 - 严格遵循 JSON 规范,可能带来更直接高效的实现路径。
 
因此,如果你的应用对 JSON 处理的性能有较高要求(例如,Web 框架的请求/响应处理、数据处理管道、API 交互等),使用 orjson 替换标准 json 库通常能带来显著的速度提升。
如何使用 orjson?
安装:
1pip install orjson使用: 它的 API 设计与标准
json库非常相似,通常可以轻松替换:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42import orjson import datetime import uuid from dataclasses import dataclass @dataclass class User: id: int name: str registered_at: datetime.datetime api_key: uuid.UUID user = User( id=1, name="Alice", registered_at=datetime.datetime.now(datetime.timezone.utc), api_key=uuid.uuid4() ) # 序列化 (dumps) # 注意:orjson.dumps 返回的是 bytes,而不是 str json_bytes = orjson.dumps(user, option=orjson.OPT_NAIVE_UTC | orjson.OPT_PASSTHROUGH_DATACLASS | orjson.OPT_SERIALIZE_UUID) print(f"Serialized (bytes): {json_bytes}") # 如果需要字符串,可以解码 json_string = json_bytes.decode('utf-8') print(f"Serialized (string): {json_string}") # 反序列化 (loads) # orjson.loads 可以接受 bytes 或 str data_from_bytes = orjson.loads(json_bytes) print(f"Deserialized from bytes: {data_from_bytes}") data_from_string = orjson.loads(json_string) print(f"Deserialized from string: {data_from_string}") # orjson 也能处理标准类型 basic_data = {"key": "value", "number": 123, "items": [1, 2, None]} basic_json_bytes = orjson.dumps(basic_data) print(f"Basic data serialized: {basic_json_bytes}") basic_deserialized = orjson.loads(basic_json_bytes) print(f"Basic data deserialized: {basic_deserialized}")注意:
orjson.dumps()默认返回bytes对象,这通常更高效,因为避免了最终的 UTF-8 编码步骤。如果需要str,需要自行解码 (.decode('utf-8'))。另外,对于datetime、dataclass、uuid等类型的序列化,可能需要通过option参数启用相应的选项。
这个详细的解释可以帮助理解 orjson 的高性能来源!