源码:https://github.com/Martin1994/JsonJitSerializer
NuGet:https://www.nuget.org/packages/MartinCl2.Text.Json.Serialization/
简介:Just-in-time 编译的 JSON 序列化
.NET Core 3.0 即将正式发布,其中一项令人振奋的功能是 corefx 集成了一个 JSON 库用来替代 JSON.NET,目前我按照 namespace 称这套库为 System.Text.Json。
这一套 JSON 库吸取了一部分 JSON.NET 的教训,将 API 的功能尽可能分离。例如它除了提供了 Object 与 String/Stream 之间的序列化与反序列化的高层 API 之外,还提供了逐 token 读写的底层 API。这为第三方开发者实现自己的 JSON 库提供了极大的方便。
了解到这一点后我意识到可以用这套底层 API(具体来说是 Utf8JsonWriter)来实现一个 just-in-time 编译(本质上其实是 IL generation)的 JSON 序列化库。
为何 JSON 序列化可以从 JIT 中受益呢?
System.Text.Json 实现 JSON 序列化的步骤是:
- 利用反射读出需要序列化的 class 的结构;
- 缓存每个需要序列化的 property,包括其名字(用 UTF-8 存储)、getter method 以及对应的 converter;
- 每次需要序列化的时候逐条读取这个结构化的缓存并利用 Utf8JsonWriter 序列化为 JSON stream。
可以注意到步骤 2 到 3 其实有点类似于解释执行的脚本语言。既然是解释执行,那自然可以有其对应的 JIT 优化,将解释的内容直接编译成可执行的代码。这样可以省去一些存取的开销和动态类型检查的开销。具体可以减小多少开销可以参照 benchmark 的结果:
Method | Mean | StdDev | Median | Min | Max | Gen 0/1k Op | Gen 1/1k Op | Allocated Memory/Op |
---|---|---|---|---|---|---|---|---|
System.Text.Json_Async | 592.6 ns | 1.3711 ns | 592.6 ns | 590.9 ns | 594.8 ns | 0.0471 | – | 304 B |
MartinCl2.Text.Json_Async | 346.0 ns | 1.6620 ns | 345.4 ns | 344.4 ns | 349.2 ns | 0.0239 | – | 152 B |