Golang 语言中怎么提升 JSON 编解码的性能?

简介: Golang 语言中怎么提升 JSON 编解码的性能?

介绍

在 Golang 语言中,我们一般会使用标准库 encoding/json 序列化/反序列化 JSON,但是因为 encoding/json 需要使用反射,所以如果在性能要求比较高的场景中,它就不太合适了。

本文我们要介绍的三方库 easyjson,它提供了快速且简单的方式去序列化和反序列化 Golang 结构体 / JSON,官方文档介绍,在性能测试中,easyjson 比标准库 encoding/json 高 4~5 倍。

easyjson 的目标是保持生成的 Golang 代码足够简单,以便它可以很容易地优化或修复,并且通过提供标准库 encoding/json 中无法提供的选项,为用户提供自定义生成代码的能力,例如生成 snake_case 名称或默认启用 omitempty 行为。

安装和生成代码

在准备使用 easyjson 之前,我们需要先安装 easyjson

安装命令:

go get -u github.com/mailru/easyjson/...

安装成功之后,我们就可以使用 easyjson 生成代码了,也非常简单,仅需运行以下命令。

生成代码命令:

easyjson -all <file>.go

运行上面这条命令,会自动生成一个文件 <file>_easyjson.go,文件中包含 <file>.go 文件中所有结构体对应的 marshaler 和 unmarshaler 方法。

需要注意的是,我们使用 easyjson 命令生成代码之前,需要设置 GOPATH 环境变量。

如果我们使用 easyjson 命令生成代码时,没有指定 -all 选项,我们需要在需要生成相应代码的结构体上方添加一个标签 //easyjson:json

我们使用 easyjson -all <file>.go 生成代码时,如果文件中个别结构体不需要生成相应代码,我们可以在该结构体上方添加一个标签 //easyjson:skip

除了 -all 选项,还有一些其他比较常用的选项,限于篇幅,我们不再赘述,感兴趣的读者朋友们可以查阅官方文档了解更多。

03

使用示例

读者朋友们阅读完以上内容后,想必一定会动手操练一把,以下是本文的示例代码,供读者朋友们做个参考,完整代码可以翻阅 GitHub。

结构体:

type User struct {
 ID uint64 `json:"id"`
 Name string `json:"name"`
}

序列化:

// 序列化
func encode() {
 user := &model.User{
  ID:   1,
  Name: "lucy",
 }
 bs, err := user.MarshalJSON()
 if err != nil {
  fmt.Println(err)
  return
 }
 fmt.Printf("encode() type=%T\nbs=%v\nstr=%s\n", bs, bs, string(bs))
}

反序列化:

// 反序列化
func decode() {
 user := new(model.User)
 str := `{"id":1,"name":"lucy"}`
 err := user.UnmarshalJSON([]byte(str))
 if err != nil {
  fmt.Println(err)
  return
 }
 fmt.Printf("decode() user=%+v\n", user)
}

04

总结

本文我们重点介绍了相比 Golang 标准库 encoding/json 性能较高的三方库 easyjson,包括安装、使用和示例代码。感兴趣的读者朋友,可以 benchmark 做个对比。

读到这里,读者朋友们可能会有个疑问,既然 easyjson 不会使用反射,为什么结构体定义时还使用 json 标签,实际上,easyjson 在生成代码时,也使用了反射。

在应用程序开发中,如果标准库可以满足需求,不建议引入三方库,导致增加应用程序的维护成本。

推荐阅读:

Go 语言学习之基础数据类型

Golang 语言中的非类型安全指针

参考资料:

https://github.com/mailru/easyjson

https://pkg.go.dev/encoding/json@go1.16.7


目录
相关文章
|
5月前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
177 4
Golang语言之管道channel快速入门篇
|
5月前
|
Go
Golang语言文件操作快速入门篇
这篇文章是关于Go语言文件操作快速入门的教程,涵盖了文件的读取、写入、复制操作以及使用标准库中的ioutil、bufio、os等包进行文件操作的详细案例。
88 4
Golang语言文件操作快速入门篇
|
5月前
|
Go
Golang语言之gRPC程序设计示例
这篇文章是关于Golang语言使用gRPC进行程序设计的详细教程,涵盖了RPC协议的介绍、gRPC环境的搭建、Protocol Buffers的使用、gRPC服务的编写和通信示例。
146 3
Golang语言之gRPC程序设计示例
|
5月前
|
安全 Go
Golang语言goroutine协程并发安全及锁机制
这篇文章是关于Go语言中多协程操作同一数据问题、互斥锁Mutex和读写互斥锁RWMutex的详细介绍及使用案例,涵盖了如何使用这些同步原语来解决并发访问共享资源时的数据安全问题。
116 4
|
3月前
|
JSON JavaScript 前端开发
Go语言中json序列化的一个小坑,建议多留意一下
在Go语言开发中,JSON因其简洁和广泛的兼容性而常用于数据交换,但其在处理数字类型时存在精度问题。本文探讨了JSON序列化的一些局限性,并介绍了两种替代方案:Go特有的gob二进制协议,以及msgpack,两者都能有效解决类型保持和性能优化的问题。
82 7
|
3月前
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
74 4
|
5月前
|
Go 调度
Golang语言goroutine协程篇
这篇文章是关于Go语言goroutine协程的详细教程,涵盖了并发编程的常见术语、goroutine的创建和调度、使用sync.WaitGroup控制协程退出以及如何通过GOMAXPROCS设置程序并发时占用的CPU逻辑核心数。
145 4
Golang语言goroutine协程篇
|
5月前
|
Prometheus Cloud Native Go
Golang语言之Prometheus的日志模块使用案例
这篇文章是关于如何在Golang语言项目中使用Prometheus的日志模块的案例,包括源代码编写、编译和测试步骤。
101 3
Golang语言之Prometheus的日志模块使用案例
|
4月前
|
前端开发 中间件 Go
实践Golang语言N层应用架构
【10月更文挑战第2天】本文介绍了如何在Go语言中使用Gin框架实现N层体系结构,借鉴了J2EE平台的多层分布式应用程序模型。文章首先概述了N层体系结构的基本概念,接着详细列出了Go语言中对应的构件名称,包括前端框架(如Vue.js、React)、Gin的处理函数和中间件、依赖注入和配置管理、会话管理和ORM库(如gorm或ent)。最后,提供了具体的代码示例,展示了如何实现HTTP请求处理、会话管理和数据库操作。
67 0
|
5月前
|
JSON Go 数据格式
Golang语言结构体链式编程与JSON序列化
这篇文章是关于Go语言中结构体链式编程与JSON序列化的教程,详细介绍了JSON格式的基本概念、结构体的序列化与反序列化、结构体标签的使用以及如何实现链式编程。
64 4