json序列号性能对比

json序列号性能对比

笔者在日常工作中对高并发的要求越来越高,在针对 QPS 50k/s 的情况下需要对 json 数据进行序列化和反序列化,如果使用官方提供的 encoding/json 包的话性能会低很多。

下面基于常用的 json 序列化/反序列化进行性能对比:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//easyjson:json
type DeviceReportData struct {
EventTime string `json:"event_time"`
AlarmEvent *AlarmEvent `json:"alarm_event"`
}

//easyjson:json
type AlarmEvent struct {
EventEnd string `json:"event_end"`
EventID string `json:"event_id"`
EventStart string `json:"event_start"`
EventType int32 `json:"event_type"`
Image string `json:"image"`
Url string `json:"url"`
ReportType int32 `json:"report_type"`
VideoEnd string `json:"video_end"`
VideoStart string `json:"video_start"`
Channel *int32 `json:"channel"` // 通道号
}

var Buf = []byte(`{"event_time":"1705976940","alarm_event":{"event_end":"1705976940","event_id":"1705976940","event_start":"1705976940","event_type":10,"image":"http://baidu.com","url":"http://baidu.com","report_type":2,"video_end":"1705976940","video_start":"1705976940","channel":null}}`)

var MapData = map[string]interface{}{
"event_time": "1705976940",
"alarm_event": map[string]interface{}{
"event_end": "1705976940",
"event_id": "1705976940",
"event_start": "1705976940",
"event_type": 10,
"image": "http://baidu.com",
"url": "http://baidu.com",
"report_type": 2,
"video_end": "1705976940",
"video_start": "1705976940",
"channel": nil,
},
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
package main

import (
"encoding/json"
"testing"

"example/json/model"

"github.com/bytedance/sonic"
jsoniter "github.com/json-iterator/go"
"github.com/mailru/easyjson"
)

func BenchmarkMarshal(b *testing.B) {
data := model.DeviceReportData{
EventTime: "1705976940",
AlarmEvent: &model.AlarmEvent{
EventEnd: "1705976940",
EventID: "1705976940",
EventStart: "1705976940",
EventType: 10,
Image: "http://test.com/cloud_ts%2F7_3301000000189651%2F1702396800_1702449469_1702449473.ts?sign=test.testn9IXLLrB%26q-sigtest.test3Dhost%26q-url-param-list%3D%26q-signature%3D22e454990aa2e1bc9903c1cde0d0952fd56",
Url: "http://test.com/cloud_ts%2F7_3301000000189651%2F1702396800_1702449469_1702449473.ts?sign=test.testn9IXLLrB%26q-sigtest.test3Dhost%26q-url-param-list%3D%26q-signature%3D22e454990aa2e1bc9903c1cde0d0952fd56",
ReportType: 2,
VideoEnd: "1705976940",
VideoStart: "1705976940",
Channel: nil,
},
}
for i := 0; i < b.N; i++ {
_, err := json.Marshal(&data)
if err != nil {
b.Error(err)
return
}
}
}

func BenchmarkMarshalSonic(b *testing.B) {
data := model.DeviceReportData{
EventTime: "1705976940",
AlarmEvent: &model.AlarmEvent{
EventEnd: "1705976940",
EventID: "1705976940",
EventStart: "1705976940",
EventType: 10,
Image: "http://test.com/cloud_ts%2F7_3301000000189651%2F1702396800_1702449469_1702449473.ts?sign=test.testn9IXLLrB%26q-sigtest.test3Dhost%26q-url-param-list%3D%26q-signature%3D22e454990aa2e1bc9903c1cde0d0952fd56",
Url: "http://test.com/cloud_ts%2F7_3301000000189651%2F1702396800_1702449469_1702449473.ts?sign=test.testn9IXLLrB%26q-sigtest.test3Dhost%26q-url-param-list%3D%26q-signature%3D22e454990aa2e1bc9903c1cde0d0952fd56",
ReportType: 2,
VideoEnd: "1705976940",
VideoStart: "1705976940",
Channel: nil,
},
}
for i := 0; i < b.N; i++ {
_, err := sonic.Marshal(&data)
if err != nil {
b.Error(err)
return
}
}
}

func BenchmarkMarshalEasyJson(b *testing.B) {
data := model.DeviceReportData{
EventTime: "1705976940",
AlarmEvent: &model.AlarmEvent{
EventEnd: "1705976940",
EventID: "1705976940",
EventStart: "1705976940",
EventType: 10,
Image: "http://test.com/cloud_ts%2F7_3301000000189651%2F1702396800_1702449469_1702449473.ts?sign=test.testn9IXLLrB%26q-sigtest.test3Dhost%26q-url-param-list%3D%26q-signature%3D22e454990aa2e1bc9903c1cde0d0952fd56",
Url: "http://test.com/cloud_ts%2F7_3301000000189651%2F1702396800_1702449469_1702449473.ts?sign=test.testn9IXLLrB%26q-sigtest.test3Dhost%26q-url-param-list%3D%26q-signature%3D22e454990aa2e1bc9903c1cde0d0952fd56",
ReportType: 2,
VideoEnd: "1705976940",
VideoStart: "1705976940",
Channel: nil,
},
}
for i := 0; i < b.N; i++ {
_, err := easyjson.Marshal(&data)
if err != nil {
b.Error(err)
return
}
}
}

func BenchmarkMarshalIterJson(b *testing.B) {
data := model.DeviceReportData{
EventTime: "1705976940",
AlarmEvent: &model.AlarmEvent{
EventEnd: "1705976940",
EventID: "1705976940",
EventStart: "1705976940",
EventType: 10,
Image: "http://test.com/cloud_ts%2F7_3301000000189651%2F1702396800_1702449469_1702449473.ts?sign=test.testn9IXLLrB%26q-sigtest.test3Dhost%26q-url-param-list%3D%26q-signature%3D22e454990aa2e1bc9903c1cde0d0952fd56",
Url: "http://test.com/cloud_ts%2F7_3301000000189651%2F1702396800_1702449469_1702449473.ts?sign=test.testn9IXLLrB%26q-sigtest.test3Dhost%26q-url-param-list%3D%26q-signature%3D22e454990aa2e1bc9903c1cde0d0952fd56",
ReportType: 2,
VideoEnd: "1705976940",
VideoStart: "1705976940",
Channel: nil,
},
}
for i := 0; i < b.N; i++ {
_, err := jsoniter.Marshal(&data)
if err != nil {
b.Error(err)
return
}
}
}

func BenchmarkUnmarshal(b *testing.B) {
for i := 0; i < b.N; i++ {
var data model.DeviceReportData
err := json.Unmarshal(model.Buf, &data)
if err != nil {
b.Error(err)
return
}
}
}

func BenchmarkUnmarshalSonic(b *testing.B) {
for i := 0; i < b.N; i++ {
var data model.DeviceReportData
err := sonic.Unmarshal(model.Buf, &data)
if err != nil {
b.Error(err)
return
}
}
}

func BenchmarkUnmarshalEasyJson(b *testing.B) {
for i := 0; i < b.N; i++ {
var data model.DeviceReportData
err := easyjson.Unmarshal(model.Buf, &data)
if err != nil {
b.Error(err)
return
}
}
}

func BenchmarkUnmarshalIterJson(b *testing.B) {
for i := 0; i < b.N; i++ {
var data model.DeviceReportData
err := jsoniter.Unmarshal(model.Buf, &data)
if err != nil {
b.Error(err)
return
}
}
}

func BenchmarkMarshalMap(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := json.Marshal(model.MapData)
if err != nil {
b.Error(err)
return
}
}
}

func BenchmarkMarshalMapSonic(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := sonic.Marshal(model.MapData)
if err != nil {
b.Error(err)
return
}
}
}

func BenchmarkMarshalMapIterJson(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := jsoniter.Marshal(model.MapData)
if err != nil {
b.Error(err)
return
}
}
}

func BenchmarkUnmarshalMap(b *testing.B) {
for i := 0; i < b.N; i++ {
data := make(map[string]interface{})
err := json.Unmarshal(model.Buf, &data)
if err != nil {
b.Error(err)
return
}
}
}

func BenchmarkUnmarshalMapSonic(b *testing.B) {
for i := 0; i < b.N; i++ {
data := make(map[string]interface{})
err := sonic.Unmarshal(model.Buf, &data)
if err != nil {
b.Error(err)
return
}
}
}

func BenchmarkUnmarshalMapIterJson(b *testing.B) {
for i := 0; i < b.N; i++ {
data := make(map[string]interface{})
err := jsoniter.Unmarshal(model.Buf, &data)
if err != nil {
b.Error(err)
return
}
}
}

序列化

  1. 结构体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ go test -benchmem -run=^$ -count=3  -bench "^BenchmarkMarshal.*$"
goos: windows
goarch: amd64
pkg: example/json
cpu: Intel(R) Core(TM) i5-9400 CPU @ 2.90GHz
BenchmarkMarshal-6 207584 5704 ns/op 2675 B/op 7 allocs/op
BenchmarkMarshal-6 210411 5742 ns/op 2675 B/op 7 allocs/op
BenchmarkMarshal-6 210532 5728 ns/op 2675 B/op 7 allocs/op
BenchmarkMarshalSonic-6 480007 2550 ns/op 2825 B/op 10 allocs/op
BenchmarkMarshalSonic-6 460984 2533 ns/op 2824 B/op 10 allocs/op
BenchmarkMarshalSonic-6 486177 2536 ns/op 2815 B/op 10 allocs/op
BenchmarkMarshalEasyJson-6 750121 1613 ns/op 1761 B/op 7 allocs/op
BenchmarkMarshalEasyJson-6 750069 1599 ns/op 1761 B/op 7 allocs/op
BenchmarkMarshalEasyJson-6 717540 1615 ns/op 1761 B/op 7 allocs/op
BenchmarkMarshalIterJson-6 599994 1955 ns/op 2682 B/op 8 allocs/op
BenchmarkMarshalIterJson-6 609241 1946 ns/op 2682 B/op 8 allocs/op
BenchmarkMarshalIterJson-6 607142 1949 ns/op 2682 B/op 8 allocs/op
PASS
ok example/json 14.752s
  1. Map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ go test -benchmem -run=^$ -count=3  -bench "^BenchmarkMarshalMap.*$"
goos: windows
goarch: amd64
pkg: example/json
cpu: Intel(R) Core(TM) i5-9400 CPU @ 2.90GHz
BenchmarkMarshalMap-6 304677 4085 ns/op 1712 B/op 33 allocs/op
BenchmarkMarshalMap-6 305149 4063 ns/op 1712 B/op 33 allocs/op
BenchmarkMarshalMap-6 300013 4073 ns/op 1712 B/op 33 allocs/op
BenchmarkMarshalMapSonic-6 1000000 1022 ns/op 360 B/op 4 allocs/op
BenchmarkMarshalMapSonic-6 1000000 1073 ns/op 362 B/op 4 allocs/op
BenchmarkMarshalMapSonic-6 1000000 1021 ns/op 359 B/op 4 allocs/op
BenchmarkMarshalMapIterJson-6 750084 1543 ns/op 544 B/op 7 allocs/op
BenchmarkMarshalMapIterJson-6 750069 1542 ns/op 544 B/op 7 allocs/op
BenchmarkMarshalMapIterJson-6 798530 1535 ns/op 544 B/op 7 allocs/op
PASS
ok example/json 10.621s

反序列号

  1. 结构体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ go test -benchmem -run=^$ -count=3  -bench "^BenchmarkUnmarshal.*$"
goos: windows
goarch: amd64
pkg: example/json
cpu: Intel(R) Core(TM) i5-9400 CPU @ 2.90GHz
BenchmarkUnmarshal-6 390900 3004 ns/op 464 B/op 13 allocs/op
BenchmarkUnmarshal-6 374978 3004 ns/op 464 B/op 13 allocs/op
BenchmarkUnmarshal-6 390684 3009 ns/op 464 B/op 13 allocs/op
BenchmarkUnmarshalSonic-6 798418 1544 ns/op 620 B/op 12 allocs/op
BenchmarkUnmarshalSonic-6 800923 1551 ns/op 619 B/op 12 allocs/op
BenchmarkUnmarshalSonic-6 749980 1538 ns/op 621 B/op 12 allocs/op
BenchmarkUnmarshalEasyJson-6 1300837 904.9 ns/op 272 B/op 9 allocs/op
BenchmarkUnmarshalEasyJson-6 1313162 914.9 ns/op 272 B/op 9 allocs/op
BenchmarkUnmarshalEasyJson-6 1316696 913.5 ns/op 272 B/op 9 allocs/op
BenchmarkUnmarshalIterJson-6 600024 1969 ns/op 768 B/op 25 allocs/op
BenchmarkUnmarshalIterJson-6 599996 1958 ns/op 768 B/op 25 allocs/op
BenchmarkUnmarshalIterJson-6 610034 1957 ns/op 768 B/op 25 allocs/op
PASS
ok example/json 17.280s
  1. Map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ go test -benchmem -run=^$ -count=3  -bench "^BenchmarkUnmarshalMap.*$"
goos: windows
goarch: amd64
pkg: example/json
cpu: Intel(R) Core(TM) i5-9400 CPU @ 2.90GHz
BenchmarkUnmarshalMap-6 270529 4412 ns/op 1950 B/op 45 allocs/op
BenchmarkUnmarshalMap-6 268683 4356 ns/op 1950 B/op 45 allocs/op
BenchmarkUnmarshalMap-6 279075 4344 ns/op 1950 B/op 45 allocs/op
BenchmarkUnmarshalMapSonic-6 600084 1906 ns/op 1736 B/op 18 allocs/op
BenchmarkUnmarshalMapSonic-6 631568 1898 ns/op 1737 B/op 18 allocs/op
BenchmarkUnmarshalMapSonic-6 631564 1903 ns/op 1740 B/op 18 allocs/op
BenchmarkUnmarshalMapIterJson-6 356742 3305 ns/op 1902 B/op 50 allocs/op
BenchmarkUnmarshalMapIterJson-6 345680 3332 ns/op 1902 B/op 50 allocs/op
BenchmarkUnmarshalMapIterJson-6 342613 3313 ns/op 1902 B/op 50 allocs/op
PASS
ok example/json 10.937s

总结

  1. 结构体,从测试结果上看 easyjson 性能是最好的,缺点是需要使用工具事先生成结构体的序列化/反序列化接口,如果忘记生成则会有问题。
    序列化:easyjson > json-iterator > sonic > encoding/json
    反序列化:easyjson > sonic > json-iterator > encoding/json

  2. map
    sonic > json-iterator > encoding/json