mirror of
https://github.com/ii64/sonic.git
synced 2026-06-20 16:45:22 +08:00
test: benchmark with github.com/goccy/go-json (#23)
chore: add benchmark result with go-json Co-authored-by: duanyi.aster <duanyi.aster@bytedance.com>
This commit is contained in:
parent
85a0d4219f
commit
936cee0d3f
9 changed files with 191 additions and 20 deletions
49
README.md
49
README.md
|
|
@ -6,30 +6,39 @@ A blazingly fast JSON serializing & deserializing library, accelerated by JI
|
|||
|
||||
## Benchmarks
|
||||
For all sizes of json and all scenes of usage, Sonic performs almost best.
|
||||
- Small (400B, 11 keys, 3 levels)
|
||||
- [Small](https://github.com/bytedance/sonic/blob/main/testdata/small.go) (400B, 11 keys, 3 levels)
|
||||

|
||||
- Medium (110KB, 300+ keys, 3 levels, with many quoted-json values)
|
||||

|
||||
- Large (550KB, 10000+ key, 6 levels)
|
||||
- [Large](https://github.com/bytedance/sonic/blob/main/testdata/twitterescaped.json) (550KB, 10000+ key, 6 levels)
|
||||

|
||||
|
||||
For a 13KB [TwitterJson](https://github.com/bytedance/sonic/blob/main/decoder/testdata_test.go#L19)(cpu i9-9880H, goarch amd64), Sonic is **1.5x** faster than [json-iterator](https://github.com/json-iterator/go) in decoding, **2.5x** faster in encoding.
|
||||
For a 13KB [TwitterJson](https://github.com/bytedance/sonic/blob/main/decoder/testdata_test.go#L19), Sonic is **1.5x** faster than [json-iterator](https://github.com/json-iterator/go) in decoding, **2.5x** faster in encoding.
|
||||
|
||||
```powershell
|
||||
BenchmarkDecoder_Generic_Sonic-16 10000 54309 ns/op 240.01 MB/s 46149 B/op 303 allocs/op
|
||||
BenchmarkDecoder_Generic_StdLib-16 10000 135268 ns/op 96.36 MB/s 50899 B/op 772 allocs/op
|
||||
BenchmarkDecoder_Generic_JsonIter-16 10000 96701 ns/op 134.80 MB/s 55791 B/op 1068 allocs/op
|
||||
BenchmarkDecoder_Binding_Sonic-16 10000 29478 ns/op 442.20 MB/s 26062 B/op 34 allocs/op
|
||||
BenchmarkDecoder_Binding_StdLib-16 10000 119348 ns/op 109.22 MB/s 10560 B/op 207 allocs/op
|
||||
BenchmarkDecoder_Binding_JsonIter-16 10000 37646 ns/op 346.25 MB/s 14673 B/op 385 allocs/op
|
||||
BenchmarkEncoder_Generic_Sonic-16 10000 25894 ns/op 503.39 MB/s 19096 B/op 42 allocs/op
|
||||
BenchmarkEncoder_Generic_JsonIter-16 10000 50275 ns/op 259.27 MB/s 13432 B/op 77 allocs/op
|
||||
BenchmarkEncoder_Generic_StdLib-16 10000 154901 ns/op 84.15 MB/s 48173 B/op 827 allocs/op
|
||||
BenchmarkEncoder_Binding_Sonic-16 10000 7373 ns/op 1768.04 MB/s 13861 B/op 4 allocs/op
|
||||
BenchmarkEncoder_Binding_JsonIter-16 10000 23223 ns/op 561.31 MB/s 9489 B/op 2 allocs/op
|
||||
BenchmarkEncoder_Binding_StdLib-16 10000 19512 ns/op 668.07 MB/s 9477 B/op 1 allocs/op
|
||||
goos: darwin
|
||||
goarch: amd64
|
||||
pkg: github.com/bytedance/sonic/encoder
|
||||
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
|
||||
BenchmarkEncoder_Generic_Sonic-16 100000 24174 ns/op 539.22 MB/s 17757 B/op 42 allocs/op
|
||||
BenchmarkEncoder_Generic_JsonIter-16 100000 44613 ns/op 292.18 MB/s 13433 B/op 77 allocs/op
|
||||
BenchmarkEncoder_Generic_GoJson-16 100000 87898 ns/op 148.30 MB/s 13234 B/op 39 allocs/op
|
||||
BenchmarkEncoder_Generic_StdLib-16 100000 133512 ns/op 97.63 MB/s 48177 B/op 827 allocs/op
|
||||
|
||||
BenchmarkEncoder_Binding_Sonic-16 100000 6058 ns/op 2151.73 MB/s 13481 B/op 4 allocs/op
|
||||
BenchmarkEncoder_Binding_JsonIter-16 100000 21223 ns/op 614.20 MB/s 9488 B/op 2 allocs/op
|
||||
BenchmarkEncoder_Binding_GoJson-16 100000 10186 ns/op 1279.74 MB/s 9480 B/op 1 allocs/op
|
||||
BenchmarkEncoder_Binding_StdLib-16 100000 17741 ns/op 734.75 MB/s 9479 B/op 1 allocs/op
|
||||
|
||||
BenchmarkDecoder_Generic_Sonic-16 100000 53344 ns/op 244.36 MB/s 50158 B/op 313 allocs/op
|
||||
BenchmarkDecoder_Generic_StdLib-16 100000 141006 ns/op 92.44 MB/s 50898 B/op 772 allocs/op
|
||||
BenchmarkDecoder_Generic_JsonIter-16 100000 106386 ns/op 122.53 MB/s 55785 B/op 1068 allocs/op
|
||||
BenchmarkDecoder_Generic_GoJson-16 100000 107184 ns/op 121.61 MB/s 65678 B/op 944 allocs/op
|
||||
|
||||
BenchmarkDecoder_Binding_Sonic-16 100000 30039 ns/op 433.94 MB/s 25259 B/op 34 allocs/op
|
||||
BenchmarkDecoder_Binding_StdLib-16 100000 131088 ns/op 99.44 MB/s 10560 B/op 207 allocs/op
|
||||
BenchmarkDecoder_Binding_JsonIter-16 100000 37988 ns/op 343.13 MB/s 14674 B/op 385 allocs/op
|
||||
BenchmarkDecoder_Binding_GoJson-16 100000 33741 ns/op 386.33 MB/s 22047 B/op 49 allocs/op
|
||||
```
|
||||
More detail see [ast/search_test.go](https://github.com/bytedance/sonic/blob/main/ast/search_test.go), [decoder/decoder_test.go](https://github.com/bytedance/sonic/blob/main/decoder/decoder_test.go), [encoder/encoder_test.go](https://github.com/bytedance/sonic/blob/main/encoder/encoder_test.go),
|
||||
More detail see [decoder/decoder_test.go](https://github.com/bytedance/sonic/blob/main/decoder/decoder_test.go), [encoder/encoder_test.go](https://github.com/bytedance/sonic/blob/main/encoder/encoder_test.go), [ast/search_test.go](https://github.com/bytedance/sonic/blob/main/ast/search_test.go), [ast/parser_test.go](https://github.com/bytedance/sonic/blob/main/ast/parser_test.go)
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
@ -119,7 +128,7 @@ For alignment to encoding/json, we provide API to pass `[]byte` as arguement, bu
|
|||
```go
|
||||
import "github.com/bytedance/sonic"
|
||||
|
||||
root, err := sonic.GetByString(_TwitterJson, "statuses", 3, "user")
|
||||
root, err := sonic.GetFromString(_TwitterJson, "statuses", 3, "user")
|
||||
a = root.GetByPath( "entities","description")
|
||||
b = root.GetByPath( "entities","url")
|
||||
c = root.GetByPath( "created_at")
|
||||
|
|
@ -130,7 +139,7 @@ In most cases of fully-load generic json, `Unmarshal()` performs better than `as
|
|||
```go
|
||||
import "github.com/bytedance/sonic"
|
||||
|
||||
node, err := sonic.GetByString(_TwitterJson, "statuses", 3, "user")
|
||||
node, err := sonic.GetFromString(_TwitterJson, "statuses", 3, "user")
|
||||
var user interface{}
|
||||
err = sonic.UnmarshalString(node.Raw(), &user)
|
||||
```
|
||||
|
|
|
|||
BIN
bench-110KB.png
BIN
bench-110KB.png
Binary file not shown.
|
Before Width: | Height: | Size: 93 KiB |
BIN
bench-400B.png
BIN
bench-400B.png
Binary file not shown.
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 82 KiB |
BIN
bench-550KB.png
BIN
bench-550KB.png
Binary file not shown.
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 87 KiB |
|
|
@ -24,6 +24,7 @@ import (
|
|||
`github.com/json-iterator/go`
|
||||
`github.com/stretchr/testify/assert`
|
||||
`github.com/stretchr/testify/require`
|
||||
gojson `github.com/goccy/go-json`
|
||||
)
|
||||
|
||||
var _BindingValue TwitterStruct
|
||||
|
|
@ -111,6 +112,18 @@ func BenchmarkDecoder_Generic_JsonIter(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecoder_Generic_GoJson(b *testing.B) {
|
||||
var w interface{}
|
||||
m := []byte(TwitterJson)
|
||||
_ = gojson.Unmarshal(m, &w)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var v interface{}
|
||||
_ = gojson.Unmarshal(m, &v)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecoder_Binding_Sonic(b *testing.B) {
|
||||
var w TwitterStruct
|
||||
_, _ = decode(TwitterJson, &w)
|
||||
|
|
@ -146,6 +159,18 @@ func BenchmarkDecoder_Binding_JsonIter(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecoder_Binding_GoJson(b *testing.B) {
|
||||
var w TwitterStruct
|
||||
m := []byte(TwitterJson)
|
||||
_ = gojson.Unmarshal(m, &w)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var v TwitterStruct
|
||||
_ = gojson.Unmarshal(m, &v)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecoder_Parallel_Generic_Sonic(b *testing.B) {
|
||||
var w interface{}
|
||||
_, _ = decode(TwitterJson, &w)
|
||||
|
|
@ -187,6 +212,20 @@ func BenchmarkDecoder_Parallel_Generic_JsonIter(b *testing.B) {
|
|||
})
|
||||
}
|
||||
|
||||
func BenchmarkDecoder_Parallel_Generic_GoJson(b *testing.B) {
|
||||
var w interface{}
|
||||
m := []byte(TwitterJson)
|
||||
_ = gojson.Unmarshal(m, &w)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
var v interface{}
|
||||
_ = gojson.Unmarshal(m, &v)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkDecoder_Parallel_Binding_Sonic(b *testing.B) {
|
||||
var w TwitterStruct
|
||||
_, _ = decode(TwitterJson, &w)
|
||||
|
|
@ -227,3 +266,18 @@ func BenchmarkDecoder_Parallel_Binding_JsonIter(b *testing.B) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkDecoder_Parallel_Binding_GoJson(b *testing.B) {
|
||||
var w TwitterStruct
|
||||
m := []byte(TwitterJson)
|
||||
_ = gojson.Unmarshal(m, &w)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
var v TwitterStruct
|
||||
_ = gojson.Unmarshal(m, &v)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
`testing`
|
||||
|
||||
`github.com/json-iterator/go`
|
||||
gojson `github.com/goccy/go-json`
|
||||
`github.com/stretchr/testify/assert`
|
||||
)
|
||||
|
||||
|
|
@ -128,6 +129,15 @@ func BenchmarkEncoder_Generic_JsonIter(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncoder_Generic_GoJson(b *testing.B) {
|
||||
_, _ = gojson.Marshal(_GenericValue)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = gojson.Marshal(_GenericValue)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncoder_Generic_StdLib(b *testing.B) {
|
||||
_, _ = json.Marshal(_GenericValue)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
|
|
@ -155,6 +165,15 @@ func BenchmarkEncoder_Binding_JsonIter(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncoder_Binding_GoJson(b *testing.B) {
|
||||
_, _ = gojson.Marshal(&_BindingValue)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = gojson.Marshal(&_BindingValue)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncoder_Binding_StdLib(b *testing.B) {
|
||||
_, _ = json.Marshal(&_BindingValue)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
|
|
@ -186,6 +205,17 @@ func BenchmarkEncoder_Parallel_Generic_JsonIter(b *testing.B) {
|
|||
})
|
||||
}
|
||||
|
||||
func BenchmarkEncoder_Parallel_Generic_GoJson(b *testing.B) {
|
||||
_, _ = gojson.Marshal(_GenericValue)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_, _ = gojson.Marshal(_GenericValue)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkEncoder_Parallel_Generic_StdLib(b *testing.B) {
|
||||
_, _ = json.Marshal(_GenericValue)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
|
|
@ -219,6 +249,17 @@ func BenchmarkEncoder_Parallel_Binding_JsonIter(b *testing.B) {
|
|||
})
|
||||
}
|
||||
|
||||
func BenchmarkEncoder_Parallel_Binding_GoJson(b *testing.B) {
|
||||
_, _ = gojson.Marshal(&_BindingValue)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_, _ = gojson.Marshal(&_BindingValue)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkEncoder_Parallel_Binding_StdLib(b *testing.B) {
|
||||
_, _ = json.Marshal(&_BindingValue)
|
||||
b.SetBytes(int64(len(TwitterJson)))
|
||||
|
|
|
|||
1
go.mod
1
go.mod
|
|
@ -5,6 +5,7 @@ go 1.15
|
|||
require (
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20210528162528-3c6c11c43ee5
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/goccy/go-json v0.7.1 // indirect
|
||||
github.com/json-iterator/go v1.1.10
|
||||
github.com/klauspost/cpuid/v2 v2.0.6
|
||||
github.com/stretchr/testify v1.7.0
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -3,6 +3,8 @@ github.com/chenzhuoyu/base64x v0.0.0-20210528162528-3c6c11c43ee5/go.mod h1:NfDzX
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/goccy/go-json v0.7.1 h1:VMhnh5gcc8De8f6m2DLvSqY1x8Jwl3btet+EqMP0QNs=
|
||||
github.com/goccy/go-json v0.7.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
|
|
|
|||
64
testdata/small.go
vendored
Normal file
64
testdata/small.go
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package testdata
|
||||
|
||||
// ffjson: skip
|
||||
// easyjson:skip
|
||||
type Book struct {
|
||||
BookId int `json:"id"`
|
||||
BookIds []int `json:"ids"`
|
||||
Title string `json:"title"`
|
||||
Titles []string `json:"titles"`
|
||||
Price float64 `json:"price"`
|
||||
Prices []float64 `json:"prices"`
|
||||
Hot bool `json:"hot"`
|
||||
Hots []bool `json:"hots"`
|
||||
Author Author `json:"author"`
|
||||
Authors []Author `json:"authors"`
|
||||
Weights []int `json:"weights"`
|
||||
}
|
||||
|
||||
// ffjson: skip
|
||||
// easyjson:skip
|
||||
type Author struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
Male bool `json:"male"`
|
||||
}
|
||||
|
||||
var book = Book{
|
||||
BookId: 12125925,
|
||||
BookIds: []int{-2147483648, 2147483647},
|
||||
Title: "未来简史-从智人到智神",
|
||||
Titles: []string{"hello", "world"},
|
||||
Price: 40.8,
|
||||
Prices: []float64{-0.1, 0.1},
|
||||
Hot: true,
|
||||
Hots: []bool{true, true, true},
|
||||
Author: author,
|
||||
Authors: []Author{author, author, author},
|
||||
Weights: nil,
|
||||
}
|
||||
|
||||
var author = Author{
|
||||
Name: "json",
|
||||
Age: 99,
|
||||
Male: true,
|
||||
}
|
||||
|
||||
var data = []byte(`{"id":12125925,"ids":[-2147483648,2147483647],"title":"未来简史-从智人到智神","titles":["hello","world"],"price":40.8,"prices":[-0.1,0.1],"hot":true,"hots":[true,true,true],"author":{"name":"json","age":99,"male":true},"authors":[{"name":"json","age":99,"male":true},{"name":"json","age":99,"male":true},{"name":"json","age":99,"male":true}],"weights":[]}`)
|
||||
Loading…
Reference in a new issue