go JSON库调研

0 概述

go json库的序列化、反序列化性能,api可用性对比调研。

1、encoding/json

go原生标准库,对go数据结构的json格式转换有很好的支持,但通过反射序列化/反序列化,性能是较差的。

2、easyjson

https://github.com/mailru/easyjson

star:4.1K,最后的正式版本2021-02。

1、快,未使用反射。(所有说自己快的go json库都会和easyjson对比一下)

2、支持序列化/反序列化。

3、2年未更新版本。

4、使用时要先生成对应结构体的操作代码,丧失了 json 的灵活性,增加维护成本,使用起来比较麻烦。

easyjson的开发模式与protobuf类似,在程序运行之前需要使用其代码工具,为每一个结构体专门生成序列化/反序列化的程序代码。每一个程序都有定制化的解析函数。但也因为这种开发模式,easyjson对业务的侵入性比较高。一方面,在go build之前需要先生成代码;另一方面,相关的JSON处理函数也不兼容原生json库。

个人不推荐,类比protobuf。

3、go-json

https://github.com/goccy/go-json

与 Go 的 encoding/json 兼容的快速 JSON 编码器/解码器

star:2.2K,最后的正式版本2023-03。

1、支持序列化/反序列化。

2、兼容原生encoding/json。

3、追求快速,缓冲区重用、消除反射...等。

4、json-iterator

https://github.com/json-iterator/go

“encoding/json”的高性能 100% 兼容的替代品

star:12.1K,最后的正式版本2021-09。

1、支持序列化/反序列化。

2、兼容原生encoding/json。

5、gjson

https://github.com/tidwall/gjson

快速获取 JSON 值 - Go 的 JSON 解析器

star:12K,最后的正式版本2022-11.

1、提供了一种快速简单的方法来从 json 文档中获取值。

2、不兼容原生encoding/json。

6、sonic

https://github.com/bytedance/sonic

一个超快的 JSON 序列化和反序列化库,字节公司开源。

star:4.4K,最后的正式版本2023-04.

1、一个超快的 JSON 序列化和反序列化库,由 JIT(即时编译)和 SIMD(单指令多数据)加速。

2、无需代码生成的运行时对象绑定

3、用于 JSON 值操作的完整 API

4、快,快,快!

5、兼容原生encoding/json。

7、jsonparser

https://github.com/buger/jsonparser

不需要模式的 Go 最快的替代 JSON 解析器之一

star:5K,最后的正式版本2021-01。

1、不需要知道有效负载的结构(例如创建结构),并允许通过提供路径来访问字段。它比标准包快 10 倍encoding/json,不分配更多内存。

2、目标是将 JSON 解析器推向性能极限,而不是牺牲合规性和开发人员用户体验。

其他

还有一些其他的go json库,由于长期未维护(更新久远)、star数相对较少等原因,例如:simplejson、ffjson、fastjson(go)等,未被纳入基准测试范围。

基准测试

struct

小struct-嵌套

type User struct {
	Id      int64   `json:"id,omitempty"`
	Name    string  `json:"name,omitempty"`
	Age     int64   `json:"age,omitempty"`
	Desc    string  `json:"desc,omitempty"`
	Address Address `json:"address"`
}

type Address struct {
	Country  string
	Province string
	City     string
}

var yzh = User{Id: 1, Name: "zihe", Age: 18, Desc: "hello world",
	Address: Address{Country: "中国", Province: "浙江", City: "你猜是不是杭州啊"},
}

4 Kb

序列化基准测试

Benchmark_Encode_SmallStruct_Json-12              141601              8562 ns/op            4196 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_GoJson-12            133881              8844 ns/op            4195 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_JsonIter-12          126854              8758 ns/op            4195 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_Sonic-12             823544              1451 ns/op            4664 B/op          5 allocs/op

Sonic速度快6-7倍,但是内存分配次数也较多。GoJson、JsonIter性能甚至不如原生Json。

反序列化基准测试

Benchmark_Json_Unmarshal1-12                       53494             22429 ns/op            4640 B/op         12 allocs/op
Benchmark_Json_GoJson-12                          390686              2997 ns/op            4098 B/op          1 allocs/op
Benchmark_Json_JsonIter-12                        281121              4275 ns/op            4394 B/op          8 allocs/op
Benchmark_Json_Sonic-12                           874654              1300 ns/op            4285 B/op          1 allocs/op
Benchmark_Json_GJson-12                          1340902               907.1 ns/op          4096 B/op          1 allocs/op
Benchmark_Json_JsonParser-12                     1000000              1029 ns/op            4096 B/op          1 allocs/op

gjson、jsonparser胜出,比go原生json快20多倍。

中等struct-嵌套

62 Kb

序列化基准测试

Benchmark_Encode_SmallStruct_Json-12                9124            119715 ns/op           66063 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_GoJson-12              8818            132278 ns/op           65907 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_JsonIter-12            8947            126720 ns/op           65930 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_Sonic-12              88861             13543 ns/op           68981 B/op          5 allocs/op

Sonic速度快7-8倍,但是内存分配次数是2.5倍。GoJson、JsonIter性能甚至不如原生Json。

反序列化基准测试

Benchmark_Json_Unmarshal1-12                        3511            317132 ns/op           67360 B/op         12 allocs/op
Benchmark_Json_GoJson-12                           28514             42155 ns/op           65573 B/op          1 allocs/op
Benchmark_Json_JsonIter-12                         20366             58975 ns/op           67148 B/op          8 allocs/op
Benchmark_Json_Sonic-12                           111320             10951 ns/op           68335 B/op          1 allocs/op
Benchmark_Json_GJson-12                           132273              9155 ns/op           65536 B/op          1 allocs/op
Benchmark_Json_JsonParser-12                      120890              9958 ns/op           65536 B/op          1 allocs/op

gjson胜出,比go原生json快30多倍。

480 Kb

序列化基准测试

Benchmark_Encode_SmallStruct_Json-12                1302            914762 ns/op          522505 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_GoJson-12              1105           1050303 ns/op          514526 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_JsonIter-12            1214            988615 ns/op          509028 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_Sonic-12              12532             84001 ns/op          505050 B/op          5 allocs/op

Sonic速度快10-11倍,但是内存分配次数是2.5倍。GoJson、JsonIter性能甚至不如原生Json。

反序列化基准测试

Benchmark_Json_Unmarshal1-12                         489           2374119 ns/op          491809 B/op         12 allocs/op
Benchmark_Json_GoJson-12                            3666            307739 ns/op          491731 B/op          1 allocs/op
Benchmark_Json_JsonIter-12                          2730            443676 ns/op          491783 B/op          8 allocs/op
Benchmark_Json_Sonic-12                            13660             75698 ns/op          503926 B/op          1 allocs/op
Benchmark_Json_GJson-12                            19275             62513 ns/op          491520 B/op          1 allocs/op
Benchmark_Json_JsonParser-12                       17703             67776 ns/op          491520 B/op          1 allocs/op

gjson胜出,比go原生json快30多倍。

较大struct-嵌套

1.6 Mb

序列化基准测试

Benchmark_Encode_SmallStruct_Json-12                 380           3184574 ns/op         1740204 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_GoJson-12               331           3532169 ns/op         1738670 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_JsonIter-12             363           3228532 ns/op         1723129 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_Sonic-12               4981            239415 ns/op         1735739 B/op          5 allocs/op

Sonic速度快12-14倍,但是内存分配次数是2.5倍。

反序列化基准测试

Benchmark_Json_Unmarshal1-12                         144           8332906 ns/op         1704224 B/op         12 allocs/op
Benchmark_Json_GoJson-12                            1011           1177656 ns/op         1704225 B/op          1 allocs/op
Benchmark_Json_JsonIter-12                           793           1556749 ns/op         1704368 B/op          8 allocs/op
Benchmark_Json_Sonic-12                             4195            301555 ns/op         1728360 B/op          1 allocs/op
Benchmark_Json_GJson-12                            10174            131980 ns/op         1703936 B/op          1 allocs/op
Benchmark_Json_JsonParser-12                        7316            183230 ns/op         1703942 B/op          1 allocs/op

gjson胜出,比go原生json快60多倍。

map

map[string]interface{},嵌套多层struct

var mapData = map[string]interface{}{
	"name": "John",
	"age":  30,
	"city": yzh,
	"addressBirth": Address{
		Country:  "中国",
		Province: "河南",
		City: "你猜是不是杭州啊"},
}

小map

11 Kb

序列化基准测试

Benchmark_Encode_SmallStruct_Json-12              143587              8259 ns/op            4195 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_GoJson-12            135042              8693 ns/op            4195 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_JsonIter-12          137720              8456 ns/op            4195 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_Sonic-12             760065              1406 ns/op            4642 B/op          5 allocs/op

Sonic速度快5-6倍,但是内存分配次数也较多。

反序列化基准测试

Benchmark_Json_Unmarshal1-12                       20538             58220 ns/op             272 B/op          8 allocs/op
Benchmark_Json_GoJson-12                          143998              8049 ns/op           12294 B/op          1 allocs/op
Benchmark_Json_JsonIter-12                        123408              9538 ns/op              72 B/op         12 allocs/op
Benchmark_Json_Sonic-12                           395383              2853 ns/op           12889 B/op          2 allocs/op
Benchmark_Json_GJson-12                           580441              2051 ns/op           12288 B/op          1 allocs/op
Benchmark_Json_JsonParser-12                      568903              2106 ns/op           12288 B/op          1 allocs/op

gjson、jsonparser速度胜出,比go原生json快20多倍。内存分配次数更少,但内存占用更多,一次把数据放到了内存缓存中。

中map

70 Kb

序列化基准测试

Benchmark_Encode_SmallStruct_Json-12                9559            118677 ns/op           65900 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_GoJson-12              8502            132664 ns/op           65900 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_JsonIter-12            9210            128783 ns/op           65908 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_Sonic-12              89984             13488 ns/op           68870 B/op          5 allocs/op

Sonic速度快8-9倍,但是内存分配次数也较多。

反序列化基准测试

Benchmark_Json_Unmarshal1-12                        3346            343629 ns/op             272 B/op          8 allocs/op
Benchmark_Json_GoJson-12                           25134             47629 ns/op           73770 B/op          1 allocs/op
Benchmark_Json_JsonIter-12                         21850             54679 ns/op              72 B/op         12 allocs/op
Benchmark_Json_Sonic-12                            83118             12879 ns/op           76618 B/op          2 allocs/op
Benchmark_Json_GJson-12                           123759              9612 ns/op           73728 B/op          1 allocs/op
Benchmark_Json_JsonParser-12                      116882             10245 ns/op           73728 B/op          1 allocs/op

gjson、jsonparser速度胜出,比go原生json快30多倍。内存分配次数更少,但内存占用更多,一次把数据放到了内存缓存中。

500 Kb

序列化基准测试

Benchmark_Encode_SmallStruct_Json-12                1114           1023233 ns/op          505429 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_GoJson-12              1095           1174343 ns/op          517592 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_JsonIter-12            1236           1184448 ns/op          508721 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_Sonic-12              10578            130489 ns/op          504201 B/op          5 allocs/op

Sonic速度快7-9倍,但是内存分配次数也较多。

反序列化基准测试

Benchmark_Json_Unmarshal1-12                         496           2379973 ns/op             272 B/op          8 allocs/op
Benchmark_Json_GoJson-12                            3532            308058 ns/op          499933 B/op          1 allocs/op
Benchmark_Json_JsonIter-12                          3140            381250 ns/op              72 B/op         12 allocs/op
Benchmark_Json_Sonic-12                            15278             74342 ns/op          505365 B/op          2 allocs/op
Benchmark_Json_GJson-12                            22629             53091 ns/op          499712 B/op          1 allocs/op
Benchmark_Json_JsonParser-12                       20624             57759 ns/op          499712 B/op          1 allocs/op

gjson、jsonparser速度胜出,比go原生json快40多倍。内存分配次数更少,但内存占用更多,一次把数据放到了内存缓存中。

大map

1.6 Mb

序列化基准测试

Benchmark_Encode_SmallStruct_Json-12                 241           5499286 ns/op         1713780 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_GoJson-12               224           5261783 ns/op         1724636 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_JsonIter-12             238           5024745 ns/op         1732964 B/op          2 allocs/op
Benchmark_Encode_SmallStruct_Sonic-12               2770            441430 ns/op         1743449 B/op          5 allocs/op

Sonic速度快12-13倍,但是内存分配次数也较多。

反序列化基准测试

Benchmark_Json_Unmarshal1-12                         100          14351250 ns/op             272 B/op          8 allocs/op
Benchmark_Json_GoJson-12                             853           1655101 ns/op         1712450 B/op          1 allocs/op
Benchmark_Json_JsonIter-12                           667           2068097 ns/op              74 B/op         12 allocs/op
Benchmark_Json_Sonic-12                             2359            441553 ns/op         1734026 B/op          2 allocs/op
Benchmark_Json_GJson-12                             4999            223816 ns/op         1712129 B/op          1 allocs/op
Benchmark_Json_JsonParser-12                        4827            298706 ns/op         1712133 B/op          1 allocs/op

gjson、jsonparser速度胜出,比go原生json快60多倍。内存分配次数更少,但内存占用更多,一次把数据放到了内存缓存中。

struct总结

序列化:Sonic速度最快,且数据越大,速度差距越大,但Sonic的内存分配次数更多些,内存分配大小无明显差距。GoJson、JsonIter性能甚至不如原生encoding/json。

反序列化:gjson最快,jsonparser次之,Sonic紧随其后,比原生encoding/json快20-70倍,数据越大,速度差距越大。

map总结

序列化:Sonic速度最快,且数据越大,速度差距越大,但Sonic的内存分配次数更多些,内存分配大小无明显差距。在map value为interface,且interface中嵌套多层struct的情况下,GoJson、JsonIter性能甚至不如原生Json。

反序列化:gjson最快,jsonparser次之,Sonic紧随其后,比原生encoding/json快20-70倍,数据越大,速度差距越大。但内存占用更多,是一次把数据放到了内存缓存中,少cpu多内存。原生encoding/json、JsonIter则是分批处理,每次操作cpu多次进行内存分配,内存占用更少,多cpu低内存。

总结

根据简单struct、嵌套struct、复杂map等类型的序列化、反序列化的基准测试,可得出:

1、序列化选择Sonic,速度在各场景都是最快的。

2、反序列化gjson最快,但gjson侧重的是从json中取值,不兼容原生encoding/json,可考虑Sonic,速度稍不如gjson,但兼容原生encoding/json。

序列化

嵌套struct:4K

嵌套struct:62K

嵌套struct:480K

嵌套struct:1.6M

复杂map:11K

复杂map:70K

复杂map:500K

复杂map:1.6M

encoding/json

8562 ns/op

119715 ns/op

914762 ns/op

3184574 ns/op

8259 ns/op

118677 ns/op

1023233 ns/op

5499286 ns/op

go-json

8844 ns/op

132278 ns/op

1050303 ns/op

3532169 ns/op

8693 ns/op

132664 ns/op

1174343 ns/op

5261783 ns/op

json-iterator

8758 ns/op

126720 ns/op

988615 ns/op

3228532 ns/op

8456 ns/op

128783 ns/op

1184448 ns/op

5024745 ns/op

sonic

1451 ns/op

13543 ns/op

84001 ns/op

239415 ns/op

1406 ns/op

13488 ns/op

130489 ns/op

441430 ns/op

反序列化

嵌套struct:4K

嵌套struct:62K

嵌套struct:480K

嵌套struct:1.6M

复杂map:11K

复杂map:70K

复杂map:500K

复杂map:1.6M

encoding/json

22429 ns/op

317132 ns/op

2374119 ns/op

8332906 ns/op

58220 ns/op

343629 ns/op

2379973 ns/op

14351250 ns/op

go-json

2997 ns/op

42155 ns/op

307739 ns/op

1177656 ns/op

8049 ns/op

47629 ns/op

308058 ns/op

1655101 ns/op

json-iterator

4275 ns/op

58975 ns/op

443676 ns/op

1556749 ns/op

9538 ns/op

54679 ns/op

381250 ns/op

2068097 ns/op

sonic

1300 ns/op

10951 ns/op

75698 ns/op

301555 ns/op

2853 ns/op

12879 ns/op

74342 ns/op

441553 ns/op

gjson

907.1 ns/op

9155 ns/op

62513 ns/op

131980 ns/op

2051 ns/op

9612 ns/op

53091 ns/op

223816 ns/op

jsonparser

1029 ns/op

9958 ns/op

67776 ns/op

183230 ns/op

2106 ns/op

10245 ns/op

57759 ns/op

298706 ns/op

代码

基准测试代码

package main

import (
	"encoding/json"
	"github.com/buger/jsonparser"
	"github.com/bytedance/sonic"
	gojson "github.com/goccy/go-json"
	jsoniter "github.com/json-iterator/go"
	"github.com/tidwall/gjson"
	"testing"
)

// var yzhBytes, _ = json.Marshal(yzh)
var yzhBytes, _ = json.Marshal(mapData)
var yzh2 User
var yzhString2 = string(yzhBytes)

func Benchmark_Encode_SmallStruct_Json(b *testing.B) {
	for i := 0; i < b.N; i++ {
		json.Marshal(yzh)
	}
}

func Benchmark_Encode_SmallStruct_GoJson(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gojson.Marshal(yzh)
	}
}

var JsonIter = jsoniter.ConfigCompatibleWithStandardLibrary

func Benchmark_Encode_SmallStruct_JsonIter(b *testing.B) {
	for i := 0; i < b.N; i++ {
		JsonIter.Marshal(yzh)
	}
}

func Benchmark_Encode_SmallStruct_Sonic(b *testing.B) {
	for i := 0; i < b.N; i++ {
		sonic.Marshal(yzh)
	}
}

func Benchmark_Json_Unmarshal1(b *testing.B) {
	for i := 0; i < b.N; i++ {
		json.Unmarshal(yzhBytes, &yzh2)
	}
}

func Benchmark_Json_GoJson(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gojson.Unmarshal(yzhBytes, &yzh2)
	}
}

var JsonIter2 = jsoniter.ConfigCompatibleWithStandardLibrary

func Benchmark_Json_JsonIter(b *testing.B) {
	for i := 0; i < b.N; i++ {
		JsonIter2.Unmarshal(yzhBytes, &yzh2)
	}
}

func Benchmark_Json_Sonic(b *testing.B) {
	for i := 0; i < b.N; i++ {
		sonic.Unmarshal(yzhBytes, &yzh2)
	}
}

var gjsonString string

func Benchmark_Json_GJson(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gjsonString = gjson.ParseBytes(yzhBytes).Raw
	}
}

var jsonparserString string

func Benchmark_Json_JsonParser(b *testing.B) {
	for i := 0; i < b.N; i++ {
		jsonparserString, _ = jsonparser.ParseString(yzhBytes)
	}
}

//func Benchmark_Json_(b *testing.B) {
//	//for i := 0; i < b.N; i++ {
//	for i := 0; i < 1; i++ {
//		fmt.Println(yzh2)
//		json.Unmarshal(yzhBytes, &yzh2)
//		fmt.Println(yzh2)
//	}
//}

//func Benchmark_Json_test(b *testing.B) {
//	var s = yzhString2
//	fmt.Println(len(s))
//}

//func Benchmark_Json_test2(b *testing.B) {
//	bytes, _ := sonic.Marshal(yzh)
//	sonic.Unmarshal(bytes, &yzh2)
//	result := gjson.ParseBytes(bytes)
//	fmt.Println(yzh2)
//	fmt.Println(result.Raw)
//}

你可能感兴趣的:(json,golang)