首页 前端知识 高性能 Rust JSON 库 sonic-rs 优化实践

高性能 Rust JSON 库 sonic-rs 优化实践

2024-06-13 21:06:41 前端知识 前端哥 298 173 我要收藏

高性能 Rust JSON 库 sonic-rs优化实践

一、sonic-rs 介绍

sonic-rs 是一个基于 SIMD 的高性能 Rust JSON 库,是 sonic JSON 库的 Rust 版本。

字节跳动 sonic 开源项目如今包含了不同语言的多个 JSON 库(如下)。其中,sonic-go 最先开源,使用了 JIT 和 SIMD 技术,sonic-cpp 使用了 C++ 模板和 SIMD 技术,这两个 JSON 库均已经在字节内部得到了较大规模的落地。在成本优化大背景下,为了帮助 Golang 业务迁移 Rust,优化 Rust JSON 性能,我们基于 JSON 方面的优化经验和实践,用纯 Rust 语言开发了高性能的 JSON 库  sonic-rs。

  • sonic(Golang JSON 库):https://github.com/bytedance/sonic

  • sonic-cpp(C++ JSON 库):https://github.com/bytedance/sonic-cpp

  • sonic-rs(Rust JSON 库):https://github.com/cloudwego/sonic-rs

sonic-rs 目前支持的 JSON 功能比较齐全,基本对齐了 serde-json 的相关功能,并且提供更加丰富的功能和更多的高性能接口。sonic-rs 的主要功能特点有:

  • 基本兼容 Serde 生态,同时支持 Volo 中的 FastStr 类型

  • 支持动态类型编解码和按需解析

  • 支持 LazyVaue,RawNumber 等类型

  • 支持 UTF-8 校验和标准浮点数精度

在性能方面,我们基于 serde-rs 官方 benchmark (https://github.com/serde-rs/json-benchmark) 提供的 Rust 结构体和 JSON 数据,对 serde-json, simd-json 和 sonic-rs 在 Rust 结构体下的解析性能进行了测试,可以发现 sonic-rs 的性能是 simd-json 的 1.5~2 倍,是 serde-json 2 倍:

二、sonic-rs 优化实践

sonic-rs 的优化主要基于 SIMD,其中部分借鉴了其他 JSON 库,如 simd-json 的优化思路。SIMD (Single instruction, multiple data) 是一种并行优化技术,可以用一条指令,并行处理多个数据。如今大多数 CPU 已经支持了各种 SIMD 指令集。例如,x86_64 架构下的 SSE,AVX2,AVX512, aarch64 架构下的 neon 指令集等。使用 SIMD 指令优化之后,对于合适的任务,程序执行的指令数量会更少,因此性能会更好。

在整体设计上,sonic-rs 并没有采用 simd-json 那种二阶段解析的思路,主要将 SIMD 优化应用于 JSON 解析和序列化中的热点,包括字符串序列化、按需解析和浮点数解析等。

1. SIMD 优化字符串序列化

字符串序列化是 JSON 序列化的热点。序列化时,需要扫描字符串中的转义字符。对于较长的字符串,逐个字节判断转义字符的操作是比较耗时的,扫描转义字符非常适合使用 SIMD 来加速。

如果用 AVX2 指令来扫描转义字符,如下面代码所示。这段 SIMD 代码在 haswell 架构下面,开 O3 优化之后,其实只有六条 SIMD 指令,即 6 条 SIMD 指令可以一次性扫描 32 个字节。相比较标量代码来说,大大减少了程序指令的数量,从而减少了程序的执行时间。

2. SIMD 优化按需解析

很多业务场景只用到 JSON 中的部分字段,很适合按需解析,在解析时跳过不需要的 JSON 字段。在跳过 JSON 字段时,难点在于如何高效跳过 JSON 中的 object 和 array。

基于 JSON 中 object 和 array 括号必须匹配的语法规则,sonic-rs 使用 SIMD 实现了高效的括号匹配算法。先通过 SIMD 得到 json object 和 array 的 bitmap,然后通过计算括号的数量来跳过 object 和 array。当发现括号匹配时,就可以跳过该 object 或 array。

3. SIMD 优化浮点数解析

浮点数解析是 JSON 解析中的一个性能热点。在字节内部,我们发现 JSON 中大部分浮点数的尾数都比较长,也适合使用 SIMD 优化。如下图,对于一段长 16 个字节的浮点数尾数 "1234342112345678":

  • 先将这段字符串读取到向量寄存器里面,此时向量的每个数字还是 ASCII 码的值。

  • 其次,用向量的减法,逐个字节减去 ASCII 码 '0' 得到 v1。这时。v1 里面的数字已经是十进制。

  • 然后,继续对 v1 里面的各个数字用向量指令做两两乘加(高位乘以 10 再加上低位),得到 v2。v2 里面的各个数已经是十进制的两位数。

  • 以此类推,利用 SIMD 指令逐层累加,最终就得到 v16。v16 里面是一个 16 位数,即最终的尾数解析结果。

  • 最后,我们再用向量指令把 v16 转成 u64 类型。

整个解析过程,不用遍历浮点数尾数的每一个字符,就能完成浮点数尾数解析。

三、sonic-rs 现状和规划

sonic-rs 已经开源几个月了,目前迭代到了 0.3 版本,已经支持 Rust stable 版本,并且支持了 aarch64 架构。sonic-rs 沉淀了一些使用文档,用以帮助各方面的开发者:

  • Golang 迁移 Rust 用户使用 sonic-rs:https://github.com/cloudwego/sonic-rs/blob/main/docs/for_Golang_user_zh.md

  • Rust serde-json 用户迁移 sonic-rs:https://github.com/cloudwego/sonic-rs/blob/main/docs/serdejson_compatibility.md

  • 性能优化细节:https://github.com/cloudwego/sonic-rs/blob/main/docs/performance_zh.md

后续,sonic-rs 会在性能,易用性和稳定性上面继续打磨,预期会支持对 Bytes/FastStr 等常见数据类型的零拷贝解析,支持运动时检测 SIMD 指令等,欢迎感兴趣的开发者一起加入我们。

```python
class BertPooler(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.dense = nn.Linear(config.hidden_size, config.hidden_size)
        self.activation = nn.Tanh()

    def forward(self, hidden_states):
        # We "pool" the model by simply taking the hidden state corresponding
        # to the first token.
        first_token_tensor = hidden_states[:, 0]
        pooled_output = self.dense(first_token_tensor)
        pooled_output = self.activation(pooled_output)
        return pooled_output
from transformers.models.bert.configuration_bert import *
import torch
config = BertConfig.from_pretrained("bert-base-uncased")
bert_pooler = BertPooler(config=config)
print("input to bert pooler size: {}".format(config.hidden_size))
batch_size = 1
seq_len = 2
hidden_size = 768
x = torch.rand(batch_size, seq_len, hidden_size)
y = bert_pooler(x)
print(y.size())
```

转载请注明出处或者链接地址:https://www.qianduange.cn//article/12055.html
标签
rust
评论
发布的文章

JQuery函数 | 选择器 | 事件

2024-06-20 00:06:11

双X轴的Echarts图

2024-06-20 00:06:08

在Vue3中使用echarts图表

2024-06-20 00:06:07

将echarts封装为js文件

2024-06-20 00:06:04

利用Echarts画地图和飞线

2024-06-20 00:06:03

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!