Json 作为一种重要的数据格式,具有良好的可读性以及自描述性,广泛地应用在各种数据传输场景中。Go 语言里面原生支持了这种数据格式的序列化以及反序列化,内部使用反射机制实现,性能有点差,在高度依赖 json 解析的应用里,往往会成为性能瓶颈,从下面的火焰图中可以发现在业务逻辑处理中,有一半多的性能消耗都是在 JSON 解析过程中,有很多第三方库帮忙解决了这个问题,接下来分析一下常用的几个库。
encoding/json
encoding/json
是官方提供的标准json, 实现RFC 7159中定义的JSON编码和解码。- 使用的时候需要预定义
struct
,原理是通过reflection
和interface
来完成工作, 性能低。
常用接口:
func Marshal(v interface{}) ([]byte, error)
生成JSONfunc Unmarshal(data []byte, v interface{}) error
解析JSON到struct
import "encoding/json" json.Marshal(&data)
json-iterator
使用modern-go/reflect2
来优化反射性能。然后就是通过大幅度减少反射操作,来提高速度。
- 完全兼容json标准库,也就是API用法完全一样,原有代码不需要改动。
- 提供了一个兼容模式(需要手动开启),可以自动转换字符串/数字弱类型问题,可以转换[]与{}弱类型问题(PHP中的array问题)。
Github: https://github.com/json-iterator/go
package main import ( "fmt" jsoniter "github.com/json-iterator/go" "github.com/json-iterator/go/extra" ) var json = jsoniter.ConfigCompatibleWithStandardLibrary func init() { // RegisterFuzzyDecoders decode input from PHP with tolerance. // It will handle string/number auto conversation, and treat empty [] as empty struct. extra.RegisterFuzzyDecoders() // 手动开启兼容模式 } type StdStruct struct { Age int `json:"age"` } func main() { s := "{\"age\": \"10\"}" d := &StdStruct{} if err := json.Unmarshal([]byte(s), d); err != nil { fmt.Println(err) } else { fmt.Println(d.Age) // 开启兼容模式后,可以解析出字符串下的10 } }
注意:只需要在main文件里通过init开启1次PHP兼容模式即可,后续引入的模块不需要重复开启。
以下是对一个对象序列化1000次,所用的耗时对比
json-iterator的on
easyjson 的思想是增加一个预编译的过程,预先生成对应结构的序列化反序列化代码,除此之外,easyjson 还放弃了一些原生库里面支持的一些不必要的特性,比如:key 类型声明,key 大小写不敏感等等,以达到更高的性能
生成代码执行 easyjson -all <file.go>
即可,如果不指定 -all
参数,只会对带有 //easyjson:json
的结构生成代码
//easyjson:json type A struct { Bar string }
性能测试
从上面的结果可以看出来:
- easyjson 无论是序列化还是反序列化都是最优的,序列化提升了1倍,反序列化提升了3倍
- jsoniter 性能也很好,接近于easyjson,关键是没有预编译过程,100%兼容原生库
- ffjson 的序列化提升并不明显,反序列化提升了1倍
- codecjson 和原生库相比,差不太多,甚至更差
- jsonparser 不太适合这样的场景,性能提升并不明显,而且没有反序列化
所以综合考虑,建议使用 jsoniter,如果追求极致的性能,考虑 easyjson。
标签:struct,iterator,easyjson,性能,golang,json,序列化 From: https://www.cnblogs.com/beatle-go/p/18221843