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


目录
相关文章
|
1月前
|
JSON Go 数据格式
【Golang】解决使用interface{}解析json数字会变成科学计数法的问题
【2月更文挑战第9天】解决使用interface{}解析json数字会变成科学计数法的问题
49 0
|
1月前
|
SQL 前端开发 Go
编程笔记 GOLANG基础 001 为什么要学习Go语言
编程笔记 GOLANG基础 001 为什么要学习Go语言
|
3月前
|
物联网 Go 网络性能优化
使用Go语言(Golang)可以实现MQTT协议的点对点(P2P)消息发送。MQTT协议本身支持多种消息收发模式
使用Go语言(Golang)可以实现MQTT协议的点对点(P2P)消息发送。MQTT协议本身支持多种消息收发模式【1月更文挑战第21天】【1月更文挑战第104篇】
101 1
|
1天前
|
Go 开发者
Golang深入浅出之-Go语言上下文(context)包:处理取消与超时
【4月更文挑战第23天】Go语言的`context`包提供`Context`接口用于处理任务取消、超时和截止日期。通过传递`Context`对象,开发者能轻松实现复杂控制流。本文解析`context`包特性,讨论常见问题和解决方案,并给出代码示例。关键点包括:1) 确保将`Context`传递给所有相关任务;2) 根据需求选择适当的`Context`创建函数;3) 定期检查`Done()`通道以响应取消请求。正确使用`context`包能提升Go程序的控制流管理效率。
6 1
|
2天前
|
安全 Go 开发者
Golang深入浅出之-Go语言并发编程面试:Goroutine简介与创建
【4月更文挑战第22天】Go语言的Goroutine是其并发模型的核心,是一种轻量级线程,能低成本创建和销毁,支持并发和并行执行。创建Goroutine使用`go`关键字,如`go sayHello(&quot;Alice&quot;)`。常见问题包括忘记使用`go`关键字、不正确处理通道同步和关闭、以及Goroutine泄漏。解决方法包括确保使用`go`启动函数、在发送完数据后关闭通道、设置Goroutine退出条件。理解并掌握这些能帮助开发者编写高效、安全的并发程序。
13 1
|
2天前
|
SQL 关系型数据库 MySQL
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
|
3天前
|
Go 开发者
Golang深入浅出之-Go语言流程控制:if、switch、for循环详解
【4月更文挑战第21天】本文介绍了Go语言中的流程控制语句,包括`if`、`switch`和`for`循环。`if`语句支持简洁的语法和初始化语句,但需注意比较运算符的使用。`switch`语句提供多分支匹配,可省略`break`,同时支持不带表达式的形式。`for`循环有多种形式,如基本循环和`for-range`遍历,遍历时修改原集合可能导致未定义行为。理解并避免易错点能提高代码质量和稳定性。通过实践代码示例,可以更好地掌握Go语言的流程控制。
11 3
Golang深入浅出之-Go语言流程控制:if、switch、for循环详解
|
3天前
|
Go
Golang深入浅出之-Go语言函数基础:定义、调用与多返回值
【4月更文挑战第21天】Go语言函数是代码组织的基本单元,用于封装可重用逻辑。本文介绍了函数定义(包括基本形式、命名、参数列表和多返回值)、调用以及匿名函数与闭包。在函数定义时,注意参数命名和注释,避免参数顺序混淆。在调用时,要检查并处理多返回值中的错误。理解闭包原理,小心处理外部变量引用,以提升代码质量和可维护性。通过实践和示例,能更好地掌握Go语言函数。
17 1
Golang深入浅出之-Go语言函数基础:定义、调用与多返回值
|
4天前
|
Go
Golang深入浅出之-Go语言基础语法:变量声明与赋值
【4月更文挑战第20天】本文介绍了Go语言中变量声明与赋值的基础知识,包括使用`var`关键字和简短声明`:=`的方式,以及多变量声明与赋值。强调了变量作用域、遮蔽、初始化与零值的重要性,并提醒读者注意类型推断时的一致性。了解这些概念有助于避免常见错误,提高编程技能和面试表现。
19 0
|
1月前
|
Go 开发工具 git
编程笔记 GOLANG基础 003 Go语言开发环境搭建
编程笔记 GOLANG基础 003 Go语言开发环境搭建