golang json性能分析详解
作者:hatlonely 发布时间:2024-05-09 14:57:46
前言
众所周知Json 作为一种重要的数据格式,具有良好的可读性以及自描述性,广泛地应用在各种数据传输场景中。Go 语言里面原生支持了这种数据格式的序列化以及反序列化,内部使用反射机制实现,性能有点差,在高度依赖 json 解析的应用里,往往会成为性能瓶颈,好在已有很多第三方库帮我们解决了这个问题,但是这么多库,对于像我这种有选择困难症的人来说,到底要怎么选择呢,下面就给大家来一一分析一下
ffjson
go get -u github.com/pquerna/ffjson
原生的库性能比较差的主要原因是使用了很多反射的机制,为了解决这个问题,ffjson 通过预编译生成代码,类型的判断在预编译阶段已经确定,避免了在运行时的反射
但也因此在编译前需要多一个步骤,需要先生成 ffjson 代码,生成代码只需要执行 ffjson <file.go>
就可以了,其中 file.go 是一个包含 json 结构体定义的 go 文件。注意这里 ffjson 是这个库提供的一个代码生成工具,直接执行上面的 go get 会把这个工具安装在 $GOPATH/bin 目录下,把 $GOPATH/bin 加到 $PATH 环境变量里面,可以全局访问
另外,如果有些结构,不想让 ffjson 生成代码,可以通过增加注释的方式
// ffjson: skip
type Foo struct {
Bar string
}
// ffjson: nodecoder
type Foo struct {
Bar string
}
easyjson
go get -u github.com/mailru/easyjson/...
easyjson 的思想和 ffjson 是一致的,都是增加一个预编译的过程,预先生成对应结构的序列化反序列化代码,除此之外,easyjson 还放弃了一些原生库里面支持的一些不必要的特性,比如:key 类型声明,key 大小写不敏感等等,以达到更高的性能
生成代码执行 easyjson -all <file.go>
即可,如果不指定 -all 参数,只会对带有 //easyjson:json 的结构生成代码
//easyjson:json
type A struct {
Bar string
}
jsoniter
go get -u github.com/json-iterator/go
这是一个很神奇的库,滴滴开发的,不像 easyjson 和 ffjson 都使用了预编译,而且 100% 兼容原生库,但是性能超级好,也不知道怎么实现的,如果有人知道的话,可以告诉我一下吗?
2018-1-28日更新,来自官方(@taowen)的回复:
没啥神奇的。就是预先缓存了对应struct的decoder实例而已。然后unsafe.Pointer省掉了一些interface{}的开销。还有一些文本解析上的优化
使用上面,你只要把所有的
import "encoding/json"
替换成
import "github.com/json-iterator/go"
var json = jsoniter.ConfigCompatibleWithStandardLibrary
就可以了,其它都不需要动
codec-json
go get -u github.com/ugorji/go/codec
这个库里面其实包含很多内容,json 只是其中的一个功能,比较老,使用起来比较麻烦,性能也不是很好
jsonparser
go get -u github.com/buger/jsonparser
严格来说,这个库不属于 json 序列化的库,只是提供了一些 json 解析的接口,使用的时候需要自己去设置结构里面的值,事实上,每次调用都需要重新解析 json 对象,性能并不是很好
就像名字暗示的那样,这个库只是一个解析库,并没有序列化的接口
性能测试
对上面这些 json 库,作了一些性能测试,测试代码在:https://github.com/hatlonely/hellogolang/blob/master/internal/json/json_benchmark_test.go,下面是在我的 Macbook 上测试的结果(实际结果和库的版本以及机器环境有关,建议自己再测试一遍):
BenchmarkMarshalStdJson-4 1000000 1097 ns/op
BenchmarkMarshalJsonIterator-4 2000000 781 ns/op
BenchmarkMarshalFfjson-4 2000000 941 ns/op
BenchmarkMarshalEasyjson-4 3000000 513 ns/op
BenchmarkMarshalCodecJson-4 1000000 1074 ns/op
BenchmarkMarshalCodecJsonWithBufio-4 1000000 2161 ns/op
BenchmarkUnMarshalStdJson-4 500000 2512 ns/op
BenchmarkUnMarshalJsonIterator-4 2000000 591 ns/op
BenchmarkUnMarshalFfjson-4 1000000 1127 ns/op
BenchmarkUnMarshalEasyjson-4 2000000 608 ns/op
BenchmarkUnMarshalCodecJson-4 20000 122694 ns/op
BenchmarkUnMarshalCodecJsonWithBufio-4 500000 3417 ns/op
BenchmarkUnMarshalJsonparser-4 2000000 877 ns/op
golang_json_performance
从上面的结果可以看出来:
easyjson 无论是序列化还是反序列化都是最优的,序列化提升了1倍,反序列化提升了3倍
jsoniter 性能也很好,接近于easyjson,关键是没有预编译过程,100%兼容原生库
ffjson 的序列化提升并不明显,反序列化提升了1倍
codecjson 和原生库相比,差不太多,甚至更差
jsonparser 不太适合这样的场景,性能提升并不明显,而且没有反序列化
所以综合考虑,建议大家使用 jsoniter,如果追求极致的性能,考虑 easyjson
参考链接
ffjson: https://github.com/pquerna/ffjson
easyjson: https://github.com/mailru/easyjson
jsoniter: https://github.com/json-iterator/go
jsonparser: https://github.com/buger/jsonparser
codecjson: http://ugorji.net/blog/go-codec-primer
来源:http://hatlonely.github.io/2018/01/28/golang-json-性能分析/


猜你喜欢
- 我就废话不多说了,大家还是直接看代码吧~#coding:utf-8import numpy as np## 改变数组的形状#将b 变成3*4
- 简介:psutil(进程和系统实用程序)是一个跨平台库,用于检索Python中运行进程和系统利用率(CPU、内存、磁盘、网络、传感器)的信息
- 环境:go 1.19.8在读多写少的情况下,即使一段时间内没有写操作,大量并发的读访问也不得不在Mutex的保护下变成串行访问,这种情况下,
- 进程是cpu资源分配的最小单元,一个进程中可以有多个线程。线程是cpu计算的最小单元。对于Python来说他的进程和线程和其他语言有差异,是
- Python果然是一款非常简明的语言,做东西非常流畅,今天又尝试了一下用Serial做了一个控制台的串口通讯,我用的下位机是STM32F10
- 前言对于使用Vue的前端而言,watch、computed和methods三个属性相信是不陌生的,是日常开发中经常使用的属性。但是对于它们的
- cron 简介在 Unix-like 操作系统中,有一个大家都很熟悉的 cli 工具,它能够来处理定时任务,周期性任务,这就是:
- 一、sort函数如果对python中的列表进行排序,可以使用List类的成员函数sort,该函数会在原空间上进行操作,对列表本身进行修改,不
- torch.argmax()函数解析1. 官网链接torch.argmax(),如下图所示:2. torch.argmax(input)函数
- 1、给定一个数据集noise-data-1.txt,该数据集中保护大量的缺失值(空格、不完整值等)。利用“全局常量”、“均值或者中位数”来填
- 测试环境 硬件:CPU 酷睿双核T5750 内存:2G 软件:Windows server 2003 + sql server 2005 O
- 之前使用smarty的时候,通常是在php程序端读取数据(一般从数据库),然后assign给模板的变量,才可以在前端使用这个变量。这样不是不
- 本文实例形式较为详细的讲述了Python socket编程。分享给大家供大家参考。具体如下:sock=socket.socket(socke
- A Process Control System 使用b/s架构、运行在类Unix系统上一个进程监控管理系统它可以使进程以daemon方式运
- 前言最新需要做一个小工具,让协作部门能够获取到服务器上的一些资源讯息,因为工具是pyqt写的所以牵扯到用python链接linux的问题,这
- Node被设计用来高效的处理I/O操作,但是你应该知道,有些类型的程序并不适合这种模式。比如,如果你打算用Node处理一个CPU密集的任务,
- 看过数据库的备份与还原。大多数都是用组件来完成的。其实可通过sql语句来完成。 由于时间关系,未对参数进行验证和界面美化。代码
- 一、闭包闭包从形式上来说是在外部函数中定义内部函数,并且内部函数引用了外部函数的变量,此变量叫做自由变量。或者说是将组成函数的语句和这些语句
- 目前python 提供了几种多线程实现方式 thread,threading,multithreading ,其中thread模块比较底层,
- 底层报错 error:cannot assign requested address原因 并发场景下 client 频繁请求端口建立tcp连