
文章插图
Sonic是一款由字节跳动开发的一个全新的高性能、适用广泛的 JSON 库 。在设计上借鉴了多款JSON库,同时为了实现对标准库的真正插拔式替换,Sonic使用了 JIT[1] (即时编译)。介绍我们在日常开发中,常常会对JSON进行序列化和反序列化 。Golang提供了encoding/json包对JSON进行Marshal/Unmarshal操作 。但是在大规模数据场景下,该包的性能和开销确实会有点不够看 。在生产环境下,JSON 序列化和反序列化会被频繁的使用到 。在测试中,CPU使用率接近 10%,其中极端情况下超过 40% 。因此,JSON 库的性能是提高机器利用率的关键问题 。
Sonic是一款由字节跳动开发的一个全新的高性能、适用广泛的 JSON 库 。在设计上借鉴了多款JSON库,同时为了实现对标准库的真正插拔式替换,Sonic使用了 JIT[1] (即时编译) 。
Sonic的特色我们可以看出:Sonic是一个主打快的JSON库 。
- 运行时对象绑定,无需代码生成
- 完备的 JSON 操作 API
- 快,更快,还要更快!
- 针对编解码动态汇编的函数调用开销,使用 JIT 技术在运行时组装与模式对应的字节码(汇编指令) ,最终将其以 Golang 函数的形式缓存在堆外内存上 。
- 针对大数据和小数据共存的实际场景,使用预处理判断(字符串大小、浮点数精度等)将 SIMD 与标量指令相结合,从而实现对实际情况的最佳适应 。
- 对于 Golang 语言编译优化的不足,使用 C/Clang 编写和编译核心计算函数,并且开发了一套 asm2asm[2] 工具,将经过充分优化的 x86 汇编代码转换为 Plan9 格式,最终加载到 Golang 运行时中 。
- 考虑到解析和跳过解析之间的速度差异很大, 惰性加载机制当然也在 AST 解析器中使用了,但以一种更具适应性和高效性的方式来降低多键查询的开销 。
- 由于 Golang 中的原生汇编函数不能被内联,发现其成本甚至超过了 C 编译器的优化所带来的改善 。所以在 JIT 中重新实现了一组轻量级的函数调用:
使用寄存器传递参数
- Sync.Map 一开始被用来缓存编解码器,但是对于准静态(读远多于写),元素较少(通常不足几十个)的场景,它的性能并不理想,所以使用开放寻址哈希和 RCU 技术重新实现了一个高性能且并发安全的缓存 。
官方建议的版本:
- Go 1.16~1.21
- linux / macOS / windows(需要 Go1.17 以上)
- Amd64 架构
# 下载sonic依赖$ go get Github.com/bytedance/sonic基本使用sonic提供了许多功能 。本文仅列举其中较为有特色的功能 。感兴趣的同学可以去看一下官方的examples序列化/反序列化sonic的使用类似于标准包encoding/json包的使用.
func base() { m := map[string]interface{}{"name": "z3","age":20, }// sonic序列化 byt, err := sonic.Marshal(&m) if err != nil {log.Println(err) } fmt.Printf("json: %+vn", string(byt)) // sonic反序列化 um := make(map[string]interface{}) err = sonic.Unmarshal(byt, &um) if err != nil {log.Println(err) } fmt.Printf("unjson: %+vn", um)}// print// json: {"name":"z3","age":20}// unjson: map[age:20 name:z3]sonic还支持流式的输入输出Sonic 支持解码 io.Reader 中输入的 json,或将对象编码为 json 后输出至 io.Writer,以处理多个值并减少内存消耗
func base() { m := map[string]interface{}{"name": "z3","age":20, } // 流式io编解码 // 编码 var encbuf bytes.Buffer enc := sonic.ConfigDefault.NewEncoder(&encbuf) if err := enc.Encode(m); err != nil {log.Fatal(err) } else {fmt.Printf("cutomize encoder: %+v", encbuf.String()) } // 解码 var decbuf bytes.Buffer decbuf.WriteString(encbuf.String()) clear(m) dec := sonic.ConfigDefault.NewDecoder(&decbuf) if err := dec.Decode(&m); err != nil {log.Fatal(err) } else {fmt.Printf("cutomize decoder: %+vn", m) }}// print// cutomize encoder: {"name":"z3","age":20}// cutomize decoder: map[age:20 name:z3]
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- EasyNetQ库:让你的分布式系统消息开发快人一步!
- C# 中的 ref 已经被放开,或许你已经不认识了
- Oracle数据库分区技术:优化大型数据集的存储效率!
- Docker容器中的Postgresql备份脚本异常解决办法
- 目前有哪些比较成功的人工智能应用?
- 为什么色准越高的显示设备就越贵
- AI要被卡脖子了?训练大模型的数据或在2026年耗尽
- 什么是知识图谱
- 什么是智能网联技术
- AI可以读取人心了 心中的小秘密还能藏多久?
