分享
  1. 首页
  2. 文章

再测Golang的JSON库

梦朝思夕 · · 2059 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

写项目一直需要进行序列化,听到了,也看到了很多同学老师对各个golang的json库进行测评。那本人为什么还要继续进行这一次测评呢? 因为实践过的知识最有说服力,也是属于自己的,我也希望看到本博文的同学老师可以修改和执行测评的代码执行一遍,我相信会有不一定的体会。 本次测评我选择了类库有:

类库

序号类库地址备注
1encoding/jsonGolan
2easyjsongithub.com/mailru/easyjson
3ffjsongithub.com/mailru/easyjson
4iterator/jsongithub.com/json-iterator/go

主要是针对上述的类型进行,本人采用了对不同的类库使用不同的结构体(仅仅是结构体名称不同,字段顺序和类型一样)。

环境

环境为MacBook Pro(Core i5处理器/8GB内存)go1.8.3 darwin/amd64

代码

bench代码如下:

package jsonbench
import (
	"encoding/gob"
	"encoding/json"
	"github.com/json-iterator/go"
	"github.com/mailru/easyjson"
	"github.com/pquerna/ffjson/ffjson"
	"testing"
)
var (
	iterator = jsoniter.ConfigCompatibleWithStandardLibrary
	// easyjson
	as = AgentService{
		ServiceName: "kaleidoscope_api",
		Version: "1517558949087295000_1298498081",
		ServiceId: "kaleidoscope_kaleidoscope.dev.igetget.com_v1.2",
		Address: "kaleidoscope.dev.igetget.com",
		Port: 80,
		Metadata: map[string]string{},
		ConnectTimeOut: 1000,
		ConnectType: "LONG",
		ReadTimeOut: 1000,
		WriteTimeOut: 1000,
		Protocol: "HTTP",
		Balance: "Random",
		Idcs: "hu,hd,hn",
		Converter: "json",
		Retry: 3,
	}
	service = as.ToService()
	asBytes, _ = json.Marshal(as)
	serviceBytes, _ = json.Marshal(service)
	asStr = string(asBytes)
	serviceStr = string(serviceBytes)
	asGonBytes, _ = GobEncode(as)
	serviceGonBytes, _ = GobEncode(service)
	// std
	asstd = AgentServiceSTD{
		ServiceName: "kaleidoscope_api",
		Version: "1517558949087295000_1298498081",
		ServiceId: "kaleidoscope_kaleidoscope.dev.igetget.com_v1.2",
		Address: "kaleidoscope.dev.igetget.com",
		Port: 80,
		Metadata: map[string]string{},
		ConnectTimeOut: 1000,
		ConnectType: "LONG",
		ReadTimeOut: 1000,
		WriteTimeOut: 1000,
		Protocol: "HTTP",
		Balance: "Random",
		Idcs: "hu,hd,hn",
		Converter: "json",
		Retry: 3,
	}
	servicestd = asstd.ToServiceSTD()
	asBytesstd, _ = json.Marshal(asstd)
	serviceBytesstd, _ = json.Marshal(servicestd)
	asStrstd = string(asBytesstd)
	serviceStrstd = string(serviceBytesstd)
	asGonBytesstd, _ = GobEncode(asstd)
	serviceGonBytesstd, _ = GobEncode(servicestd)
)
// go test -bench=".*"
func init() {
	gob.Register(AgentService{})
}
func Benchmark_STD_Marshal1(b *testing.B) {
	for i := 0; i < b.N*10; i++ {
		_, err := json.Marshal(asstd)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_STD_Marshal2(b *testing.B) {
	for i := 0; i < b.N*10; i++ {
		_, err := json.Marshal(servicestd)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_EASYJSON_STD_Marshal1(b *testing.B) {
	for i := 0; i < b.N*10; i++ {
		_, err := json.Marshal(as)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_EASYJSON_STD_Marshal2(b *testing.B) {
	for i := 0; i < b.N*10; i++ {
		_, err := json.Marshal(service)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_EASYJSON_Marshal1(b *testing.B) {
	for i := 0; i < b.N*10; i++ {
		_, err := easyjson.Marshal(as)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_EASYJSON_Marshal2(b *testing.B) {
	for i := 0; i < b.N*10; i++ {
		_, err := easyjson.Marshal(service)
		if err != nil {
			b.Error(err)
		}
	}
}
//
func Benchmark_ITERATOR_Marshal1(b *testing.B) {
	for i := 0; i < b.N*10; i++ {
		_, err := iterator.Marshal(asstd)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_ITERATOR_Marshal2(b *testing.B) {
	for i := 0; i < b.N*10; i++ {
		_, err := iterator.Marshal(servicestd)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_FFJSON_Marshal1(b *testing.B) {
	for i := 0; i < b.N*10; i++ {
		_, err := ffjson.Marshal(asstd)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_FFJSON_Marshal2(b *testing.B) {
	for i := 0; i < b.N*10; i++ {
		_, err := ffjson.Marshal(servicestd)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_GOB_Encode1(b *testing.B) {
	for i := 0; i < b.N*10; i++ {
		as.Port = i
		GobEncode(as)
	}
}
func Benchmark_GOB_Encode2(b *testing.B) {
	for i := 0; i < b.N*10; i++ {
		GobEncode(service)
	}
}
func Benchmark_STD_Unmarshal1(b *testing.B) {
	tmp := AgentServiceSTD{}
	for i := 0; i < b.N*10; i++ {
		as.Port = i
		err := json.Unmarshal(asBytesstd, &tmp)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_STD_Unmarshal2(b *testing.B) {
	tmp := ServiceSTD{}
	for i := 0; i < b.N*10; i++ {
		as.Port = i
		err := json.Unmarshal(serviceBytesstd, &tmp)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_EASYJSON_STD_Unmarshal1(b *testing.B) {
	tmp := AgentService{}
	for i := 0; i < b.N*10; i++ {
		as.Port = i
		err := json.Unmarshal(asBytes, &tmp)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_EASYJSON_STD_Unmarshal2(b *testing.B) {
	tmp := Service{}
	for i := 0; i < b.N*10; i++ {
		as.Port = i
		err := json.Unmarshal(serviceBytes, &tmp)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_EASYJSON_Unmarshal1(b *testing.B) {
	tmp := AgentService{}
	for i := 0; i < b.N*10; i++ {
		as.Port = i
		err := easyjson.Unmarshal(asBytes, &tmp)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_EASYJSON_Unmarshal2(b *testing.B) {
	tmp := Service{}
	for i := 0; i < b.N*10; i++ {
		as.Port = i
		err := easyjson.Unmarshal(serviceBytes, &tmp)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_ITERATOR_UnMarshal1(b *testing.B) {
	tmp := ServiceSTD{}
	for i := 0; i < b.N*10; i++ {
		as.Port = i
		err := iterator.Unmarshal(serviceBytesstd, &tmp)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_ITERATOR_UnMarshal2(b *testing.B) {
	tmp := ServiceSTD{}
	for i := 0; i < b.N*10; i++ {
		as.Port = i
		err := iterator.Unmarshal(serviceBytesstd, &tmp)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_FFJSON_UnMarshal1(b *testing.B) {
	tmp := ServiceSTD{}
	for i := 0; i < b.N*10; i++ {
		as.Port = i
		err := ffjson.Unmarshal(serviceBytesstd, &tmp)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_FFJSON_UnMarshal2(b *testing.B) {
	tmp := ServiceSTD{}
	for i := 0; i < b.N*10; i++ {
		as.Port = i
		err := ffjson.Unmarshal(serviceBytesstd, &tmp)
		if err != nil {
			b.Error(err)
		}
	}
}
func Benchmark_GOB_Decode1(b *testing.B) {
	tmp := AgentService{}
	for i := 0; i < b.N*10; i++ {
		as.Port = i
		GobDecode(asGonBytes, &tmp)
	}
}
func Benchmark_GOB_Decode2(b *testing.B) {
	tmp := Service{}
	for i := 0; i < b.N*10; i++ {
		as.Port = i
		GobDecode(serviceGonBytes, &tmp)
	}
}

执行命令:

go test -bench=".*"

测评结果;

$ go test -bench=".*"
Benchmark_STD_Marshal1-4 50000 31224 ns/op
Benchmark_STD_Marshal2-4 30000 49598 ns/op
Benchmark_EASYJSON_STD_Marshal1-4 30000 45778 ns/op
Benchmark_EASYJSON_STD_Marshal2-4 30000 50440 ns/op
Benchmark_EASYJSON_Marshal1-4 100000 14387 ns/op
Benchmark_EASYJSON_Marshal2-4 100000 16009 ns/op
Benchmark_ITERATOR_Marshal1-4 100000 14899 ns/op
Benchmark_ITERATOR_Marshal2-4 100000 21629 ns/op
Benchmark_FFJSON_Marshal1-4 50000 31633 ns/op
Benchmark_FFJSON_Marshal2-4 30000 51668 ns/op
Benchmark_GOB_Encode1-4 20000 97099 ns/op
Benchmark_GOB_Encode2-4 10000 153158 ns/op
Benchmark_STD_Unmarshal1-4 20000 89211 ns/op
Benchmark_STD_Unmarshal2-4 20000 76442 ns/op
Benchmark_EASYJSON_STD_Unmarshal1-4 30000 57695 ns/op
Benchmark_EASYJSON_STD_Unmarshal2-4 20000 66269 ns/op
Benchmark_EASYJSON_Unmarshal1-4 100000 19028 ns/op
Benchmark_EASYJSON_Unmarshal2-4 100000 22035 ns/op
Benchmark_ITERATOR_UnMarshal1-4 50000 35942 ns/op
Benchmark_ITERATOR_UnMarshal2-4 50000 36462 ns/op
Benchmark_FFJSON_UnMarshal1-4 20000 80290 ns/op
Benchmark_FFJSON_UnMarshal2-4 20000 78431 ns/op
Benchmark_GOB_Decode1-4 3000 377698 ns/op
Benchmark_GOB_Decode2-4 3000 463472 ns/op
PASS
ok studygo/jsonbench 49.174s

结论

  1. 哪一个类库最快?
    答:是测评类库中最快的。速度:easyjson => iterator => encoding/json => ffjson
  2. 是否存在坑?
    答:easyjson有一个坑,从代码中可以看到Benchmark_EASYJSON_STD_*的方法,是因为easyjson生成的代码中已经包含了MarshalJSONUnmarshalJSON方法,那么只要对这些结构体执行json.marshalJSONjson.UnmarshalJSON都会默认调用easyjson生成的方法。本人运行多次,都会发现调用easyjson生成的MarshalJSON方法比标准库中的慢一些达到50%左右,但是调用easyjson生成的UnmarshalJSON比标准库的快一些大概20%。
  3. 如何选择?
    答:easyjson速度虽然比较快,但也是存在一些不适合的场景,比如如果需要对interface接口进行序列化时候。所以建议采用easyjson与标准库结合。

有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:梦朝思夕

查看原文:再测Golang的JSON库

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
2059 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏