mirror of
https://github.com/ii64/sonic.git
synced 2026-06-21 00:46:43 +08:00
doc: update readme (#143)
* doc: update readme * test: add SetOne_XX() benchmarks * doc: update bechmark charts * doc: fix possible typos Co-authored-by: liuqiang <liuqiang.06@bytedance.com> Co-authored-by: duanyi.aster <duanyi.aster@bytedance.com>
This commit is contained in:
parent
49df11ef83
commit
3f2bab552b
12 changed files with 459 additions and 205 deletions
136
README.md
136
README.md
|
|
@ -3,7 +3,7 @@
|
|||
A blazingly fast JSON serializing & deserializing library, accelerated by JIT (just-in-time compiling) and SIMD (single-instruction-multiple-data).
|
||||
|
||||
## Requirement
|
||||
- Go 1.15/1.16
|
||||
- Go 1.15/1.16/1.17
|
||||
- Linux/darwin OS
|
||||
- Amd64 CPU with AVX instruction set
|
||||
|
||||
|
|
@ -13,65 +13,67 @@ A blazingly fast JSON serializing & deserializing library, accelerated by JI
|
|||
- Fast, fast, fast!
|
||||
|
||||
## Benchmarks
|
||||
For **all sizes** of json and **all cases** of usage, **Sonic performs best**.
|
||||
- [Small](https://github.com/bytedance/sonic/blob/main/testdata/small.go) (400B, 11 keys, 3 layers)
|
||||

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

|
||||
For **all sizes** of json and **all scenarios** of usage, **Sonic performs best**.
|
||||
- [Medium](https://github.com/bytedance/sonic/blob/main/decoder/testdata_test.go#L19) (13KB, 300+ key, 6 layers)
|
||||
|
||||
**For medium data, Sonic's speed is `2.6x times` of [json-iterator's](https://github.com/json-iterator/go) in `decoding`, `2.5x times` in `encoding`,and `8.3x times` in `searching`.**
|
||||
|
||||
```powershell
|
||||
goversion: 1.17.1
|
||||
goos: darwin
|
||||
goarch: amd64
|
||||
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
|
||||
BenchmarkEncoder_Generic_Sonic-16 100000 25547 ns/op 510.23 MB/s 13762 B/op 4 allocs/op
|
||||
BenchmarkEncoder_Generic_JsonIter-16 100000 44526 ns/op 292.75 MB/s 13433 B/op 77 allocs/op
|
||||
BenchmarkEncoder_Generic_StdLib-16 100000 134480 ns/op 96.93 MB/s 48177 B/op 827 allocs/op
|
||||
BenchmarkEncoder_Binding_Sonic-16 100000 6658 ns/op 1957.74 MB/s 14156 B/op 4 allocs/op
|
||||
BenchmarkEncoder_Binding_JsonIter-16 100000 21367 ns/op 610.05 MB/s 9487 B/op 2 allocs/op
|
||||
BenchmarkEncoder_Binding_StdLib-16 100000 17558 ns/op 742.41 MB/s 9480 B/op 1 allocs/op
|
||||
BenchmarkEncoder_Parallel_Generic_Sonic-16 100000 4562 ns/op 2857.18 MB/s 10957 B/op 4 allocs/op
|
||||
BenchmarkEncoder_Parallel_Generic_JsonIter-16 100000 10943 ns/op 1191.21 MB/s 13449 B/op 77 allocs/op
|
||||
BenchmarkEncoder_Parallel_Generic_StdLib-16 100000 52174 ns/op 249.84 MB/s 48218 B/op 827 allocs/op
|
||||
BenchmarkEncoder_Parallel_Binding_Sonic-16 100000 1422 ns/op 9168.12 MB/s 11030 B/op 4 allocs/op
|
||||
BenchmarkEncoder_Parallel_Binding_JsonIter-16 100000 4630 ns/op 2815.35 MB/s 9496 B/op 2 allocs/op
|
||||
BenchmarkEncoder_Parallel_Binding_StdLib-16 100000 4977 ns/op 2619.08 MB/s 9488 B/op 1 allocs/op
|
||||
BenchmarkEncoder_Generic_Sonic 25181 ns/op 517.65 MB/s 13035 B/op 4 allocs/op
|
||||
BenchmarkEncoder_Generic_JsonIter 43765 ns/op 297.84 MB/s 13433 B/op 77 allocs/op
|
||||
BenchmarkEncoder_Generic_StdLib 108776 ns/op 119.83 MB/s 49137 B/op 827 allocs/op
|
||||
BenchmarkEncoder_Binding_Sonic 6282 ns/op 2075.01 MB/s 13765 B/op 4 allocs/op
|
||||
BenchmarkEncoder_Binding_JsonIter 20740 ns/op 628.51 MB/s 9487 B/op 2 allocs/op
|
||||
BenchmarkEncoder_Binding_StdLib 16661 ns/op 782.34 MB/s 9479 B/op 1 allocs/op
|
||||
BenchmarkEncoder_Parallel_Generic_Sonic-16 4072 ns/op 3200.89 MB/s 11052 B/op 4 allocs/op
|
||||
BenchmarkEncoder_Parallel_Generic_JsonIter-16 11379 ns/op 1145.52 MB/s 13458 B/op 77 allocs/op
|
||||
BenchmarkEncoder_Parallel_Generic_StdLib-16 50635 ns/op 257.43 MB/s 49183 B/op 827 allocs/op
|
||||
BenchmarkEncoder_Parallel_Binding_Sonic-16 1304 ns/op 9994.64 MB/s 10925 B/op 4 allocs/op
|
||||
BenchmarkEncoder_Parallel_Binding_JsonIter-16 6072 ns/op 2146.76 MB/s 9505 B/op 2 allocs/op
|
||||
BenchmarkEncoder_Parallel_Binding_StdLib-16 3510 ns/op 3713.89 MB/s 9481 B/op 1 allocs/op
|
||||
|
||||
BenchmarkDecoder_Generic_Sonic-16 100000 57247 ns/op 227.70 MB/s 49727 B/op 313 allocs/op
|
||||
BenchmarkDecoder_Generic_StdLib-16 100000 139698 ns/op 93.31 MB/s 50898 B/op 772 allocs/op
|
||||
BenchmarkDecoder_Generic_JsonIter-16 100000 101967 ns/op 127.84 MB/s 55787 B/op 1068 allocs/op
|
||||
BenchmarkDecoder_Binding_Sonic-16 100000 28254 ns/op 461.35 MB/s 25062 B/op 34 allocs/op
|
||||
BenchmarkDecoder_Binding_StdLib-16 100000 123779 ns/op 105.31 MB/s 10560 B/op 207 allocs/op
|
||||
BenchmarkDecoder_Binding_JsonIter-16 100000 38253 ns/op 340.75 MB/s 14674 B/op 385 allocs/op
|
||||
BenchmarkDecoder_Parallel_Generic_Sonic-16 100000 10171 ns/op 1281.59 MB/s 49458 B/op 313 allocs/op
|
||||
BenchmarkDecoder_Parallel_Generic_StdLib-16 100000 54916 ns/op 237.36 MB/s 50907 B/op 772 allocs/op
|
||||
BenchmarkDecoder_Parallel_Generic_JsonIter-16 100000 48286 ns/op 269.95 MB/s 55811 B/op 1068 allocs/op
|
||||
BenchmarkDecoder_Parallel_Binding_Sonic-16 100000 5282 ns/op 2467.83 MB/s 24683 B/op 34 allocs/op
|
||||
BenchmarkDecoder_Parallel_Binding_StdLib-16 100000 31875 ns/op 408.94 MB/s 10559 B/op 207 allocs/op
|
||||
BenchmarkDecoder_Parallel_Binding_JsonIter-16 100000 13810 ns/op 943.90 MB/s 14679 B/op 385 allocs/op
|
||||
BenchmarkDecoder_Generic_Sonic 53843 ns/op 242.09 MB/s 49779 B/op 313 allocs/op
|
||||
BenchmarkDecoder_Generic_StdLib 130402 ns/op 99.96 MB/s 50868 B/op 772 allocs/op
|
||||
BenchmarkDecoder_Generic_JsonIter 92810 ns/op 140.45 MB/s 55788 B/op 1068 allocs/op
|
||||
BenchmarkDecoder_Binding_Sonic 29793 ns/op 437.52 MB/s 24778 B/op 34 allocs/op
|
||||
BenchmarkDecoder_Binding_StdLib 121206 ns/op 107.54 MB/s 10576 B/op 208 allocs/op
|
||||
BenchmarkDecoder_Binding_JsonIter 36099 ns/op 361.09 MB/s 14674 B/op 385 allocs/op
|
||||
BenchmarkDecoder_Parallel_Generic_Sonic-16 10319 ns/op 1263.21 MB/s 49423 B/op 313 allocs/op
|
||||
BenchmarkDecoder_Parallel_Generic_StdLib-16 58526 ns/op 222.72 MB/s 50875 B/op 772 allocs/op
|
||||
BenchmarkDecoder_Parallel_Generic_JsonIter-16 60156 ns/op 216.69 MB/s 55812 B/op 1068 allocs/op
|
||||
BenchmarkDecoder_Parallel_Binding_Sonic-16 7265 ns/op 1794.18 MB/s 24952 B/op 34 allocs/op
|
||||
BenchmarkDecoder_Parallel_Binding_StdLib-16 44000 ns/op 296.25 MB/s 10575 B/op 208 allocs/op
|
||||
BenchmarkDecoder_Parallel_Binding_JsonIter-16 21029 ns/op 619.86 MB/s 14678 B/op 385 allocs/op
|
||||
|
||||
BenchmarkSearchOne_Gjson-16 100000 8992 ns/op 1448.28 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkSearchOne_Jsoniter-16 100000 58313 ns/op 223.33 MB/s 27936 B/op 647 allocs/op
|
||||
BenchmarkSearchOne_Sonic-16 100000 10497 ns/op 1240.61 MB/s 29 B/op 1 allocs/op
|
||||
BenchmarkSearchOne_Parallel_Gjson-16 100000 1046 ns/op 12449.59 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkSearchOne_Parallel_Jsoniter-16 100000 16080 ns/op 809.88 MB/s 27942 B/op 647 allocs/op
|
||||
BenchmarkSearchOne_Parallel_Sonic-16 100000 1435 ns/op 9074.18 MB/s 285 B/op 1 allocs/op
|
||||
BenchmarkGetOne_Sonic 17070 ns/op 762.94 MB/s 29 B/op 1 allocs/op
|
||||
BenchmarkGetOne_Gjson 19714 ns/op 660.59 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkGetOne_Jsoniter 99281 ns/op 131.17 MB/s 27936 B/op 647 allocs/op
|
||||
BenchmarkSetOne_Sonic 23730 ns/op 548.80 MB/s 1883 B/op 17 allocs/op
|
||||
BenchmarkSetOne_Sjson 57680 ns/op 225.78 MB/s 52180 B/op 9 allocs/op
|
||||
BenchmarkSetOne_Jsoniter 104018 ns/op 125.20 MB/s 45859 B/op 964 allocs/op
|
||||
BenchmarkGetOne_Parallel_Sonic-16 2010 ns/op 6479.41 MB/s 114 B/op 1 allocs/op
|
||||
BenchmarkGetOne_Parallel_Gjson-16 1815 ns/op 7176.39 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkGetOne_Parallel_Jsoniter-16 23261 ns/op 559.86 MB/s 27942 B/op 647 allocs/op
|
||||
BenchmarkSetOne_Parallel_Sonic-16 2007 ns/op 6487.78 MB/s 2202 B/op 17 allocs/op
|
||||
BenchmarkSetOne_Parallel_Sjson-16 12422 ns/op 1048.40 MB/s 52180 B/op 9 allocs/op
|
||||
BenchmarkSetOne_Parallel_Jsoniter-16 39204 ns/op 332.18 MB/s 45889 B/op 964 allocs/op
|
||||
```
|
||||
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), [ast/node_test.go](https://github.com/bytedance/sonic/blob/main/ast/node_test.go)
|
||||
- [Small](https://github.com/bytedance/sonic/blob/main/testdata/small.go) (400B, 11 keys, 3 layers)
|
||||

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

|
||||
|
||||
See [bench.sh](https://github.com/bytedance/sonic/blob/main/bench.sh) for benchmark codes.
|
||||
|
||||
## How it works
|
||||
See [INTRODUCTION.md](INTRODUCTION.md)
|
||||
|
||||
## Fuzzing
|
||||
[sonic-fuzz](https://github.com/liuq19/sonic-fuzz) is the repository for fuzzing tests. If you find any bug, please report the issue to sonic.
|
||||
See [INTRODUCTION.md](INTRODUCTION.md).
|
||||
|
||||
## Usage
|
||||
|
||||
### Marshal/Unmarshal
|
||||
|
||||
The behaviors are mostly consistent with encoding/json, except some uncommon escaping (see [issue4](https://github.com/bytedance/sonic/issues/4))
|
||||
Their behaviors are mostly consistent with `encoding/json`, except two escaping form (see [issue4](https://github.com/bytedance/sonic/issues/4)) that is **NOT** in conformity to [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259).
|
||||
```go
|
||||
import "github.com/bytedance/sonic"
|
||||
|
||||
|
|
@ -118,7 +120,6 @@ import "github.com/bytedance/sonic/encoder"
|
|||
m := map[string]interface{}{}
|
||||
v, err := encoder.Encode(m, encoder.SortMapKeys)
|
||||
```
|
||||
**Caution**: sonic encode struct in order of its original field declaration, so if you want to sort a struct's keys like the map's, just rewrite your struct.
|
||||
|
||||
### Print Syntax Error
|
||||
```go
|
||||
|
|
@ -211,20 +212,23 @@ Since Sonic uses [golang-asm](https://github.com/twitchyliquid64/golang-asm) as
|
|||
import (
|
||||
"reflect"
|
||||
"github.com/bytedance/sonic"
|
||||
)
|
||||
|
||||
func init() {
|
||||
var v HugeStruct
|
||||
err := sonic.Pretouch(reflect.TypeOf(v))
|
||||
}
|
||||
"github.com/bytedance/sonic/option"
|
||||
)
|
||||
|
||||
func init() {
|
||||
var v HugeStruct
|
||||
// For most large types (nesting depth <= 5)
|
||||
err := sonic.Pretouch(reflect.TypeOf(v))
|
||||
// If the type is too deep nesting (nesting depth > 5),
|
||||
// you can set compile recursive depth in Pretouch for better stability in JIT.
|
||||
err := sonic.Pretouch(reflect.TypeOf(v), option.WithCompileRecursiveDepth(depth))
|
||||
```
|
||||
**CAUTION:** use the **STRUCT instead of its POINTER** to `Pretouch()`, otherwise it won't work when you pass the pointer to `Marshal()/Unmarshal()`!
|
||||
|
||||
### Pass string or []byte?
|
||||
For alignment to encoding/json, we provide API to pass `[]byte` as argument, but the string-to-bytes copy is conducted at the same time considering safety, which may lose performance when origin JSON is huge. Therefore, you can use `UnmarshalString`, `GetFromString` to pass a string, as long as your origin data is a string or **nocopy-cast** is safe for your []byte.
|
||||
For alignment to `encoding/json`, we provide API to pass `[]byte` as an argument, but the string-to-bytes copy is conducted at the same time considering safety, which may lose performance when origin JSON is huge. Therefore, you can use `UnmarshalString` and `GetFromString` to pass a string, as long as your origin data is a string or **nocopy-cast** is safe for your []byte.
|
||||
|
||||
### Better performance for generic deserializing
|
||||
In most cases, `Unmarshal()` with schemalized data performs better than `ast.Loads()`/`node.Interface()` with generic data. But if you only have a schema for partial json, you can combine `Get()` and `Unmarshal()` together:
|
||||
### Better performance for generic data
|
||||
In **fully-parsed** scenario, `Unmarshal()` performs better than `Get()`+`Node.Interface()`. But if you only have a part of schema for specific json, you can combine `Get()` and `Unmarshal()` together:
|
||||
```go
|
||||
import "github.com/bytedance/sonic"
|
||||
|
||||
|
|
@ -232,14 +236,20 @@ node, err := sonic.GetFromString(_TwitterJson, "statuses", 3, "user")
|
|||
var user User // your partial schema...
|
||||
err = sonic.UnmarshalString(node.Raw(), &user)
|
||||
```
|
||||
Even if you don't have any schema, Use `InterfaceUseNode()` as the container of generic values instead of `Map()` or `Interface()`:
|
||||
Even if you don't have any schema, use `ast.Node` as the container of generic values instead of `map` or `interface`:
|
||||
```go
|
||||
import "github.com/bytedance/sonic"
|
||||
|
||||
node, err := sonic.GetFromString(_TwitterJson, "statuses", 3, "user")
|
||||
user := node.InterfaceUseNode() // use node.Interface() as little as possible
|
||||
root, err := sonic.GetFromString(_TwitterJson)
|
||||
user := root.GetByPath("statuses", 3, "user") // === root.Get("status").Index(3).Get("user")
|
||||
err = user.Check()
|
||||
|
||||
// err = user.LoadAll() // only call this when you want to use 'user' concurrently...
|
||||
go someFunc(user)
|
||||
```
|
||||
Why?
|
||||
1. using `Interface()` means Sonic must parse all the underlying values, while in most cases you only need several of them;
|
||||
2. `map[x]` is not efficient enough compared to `array[x]`, but `ast.Node` can use `Index()`, for either array or object node;
|
||||
3. `map`'s performance degrades a lot once rehashing triggered, but `ast.Node` doesn't has this concern;
|
||||
Why? Because `ast.Node` stores its children using `array`:
|
||||
- `Map`'s performance degrades a lot once rehashing triggered, but `ast.Node` doesn't have this concern;
|
||||
- **Hashing** (`map[x]`) is not as efficient as **Indexing** (`array[x]`), which `ast.Node` can conduct on **both array and object**.
|
||||
- Using `Interface()`/`Map()` means Sonic must parse all the underlying values, while in most cases you don't need them all;
|
||||
|
||||
**CAUTION:** `ast.Node` **DOESN'T** ensure concurrent security directly, due to its **lazy-load** design. However, your can call `Node.Load()`/`Node.LoadAll()` to achieve that, which may bring performance reduction while it still works faster than converting to `map` or `interface{}`
|
||||
|
|
@ -24,12 +24,9 @@ import (
|
|||
`testing`
|
||||
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
jsoniter `github.com/json-iterator/go`
|
||||
`github.com/stretchr/testify/assert`
|
||||
)
|
||||
|
||||
var parallelism = 4
|
||||
|
||||
func TestLoadAll(t *testing.T) {
|
||||
e := Node{}
|
||||
err := e.Load()
|
||||
|
|
@ -770,7 +767,6 @@ func TestNodeAdd(t *testing.T) {
|
|||
|
||||
func BenchmarkLoadNode(b *testing.B) {
|
||||
b.Run("Interface()", func(b *testing.B) {
|
||||
b.SetParallelism(parallelism)
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
|
|
@ -785,7 +781,6 @@ func BenchmarkLoadNode(b *testing.B) {
|
|||
})
|
||||
|
||||
b.Run("LoadAll()", func(b *testing.B) {
|
||||
b.SetParallelism(parallelism)
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
|
|
@ -800,7 +795,6 @@ func BenchmarkLoadNode(b *testing.B) {
|
|||
})
|
||||
|
||||
b.Run("InterfaceUseNode()", func(b *testing.B) {
|
||||
b.SetParallelism(parallelism)
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
|
|
@ -815,7 +809,6 @@ func BenchmarkLoadNode(b *testing.B) {
|
|||
})
|
||||
|
||||
b.Run("Load()", func(b *testing.B) {
|
||||
b.SetParallelism(parallelism)
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
|
|
@ -836,7 +829,6 @@ func BenchmarkNodeGetByPath(b *testing.B) {
|
|||
b.Fatalf("decode failed: %v", derr.Error())
|
||||
}
|
||||
_, _ = root.GetByPath("statuses", 3, "entities", "hashtags", 0, "text").String()
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
|
|
@ -846,14 +838,13 @@ func BenchmarkNodeGetByPath(b *testing.B) {
|
|||
})
|
||||
}
|
||||
|
||||
func BenchmarkStructGetByPath_Jsoniter(b *testing.B) {
|
||||
func BenchmarkStructGetByPath(b *testing.B) {
|
||||
var root = _TwitterStruct{}
|
||||
err := jsoniter.Unmarshal([]byte(_TwitterJson), &root)
|
||||
err := json.Unmarshal([]byte(_TwitterJson), &root)
|
||||
if err != nil {
|
||||
b.Fatalf("unmarshal failed: %v", err)
|
||||
}
|
||||
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
|
|
@ -976,7 +967,6 @@ func BenchmarkNodeSet(b *testing.B) {
|
|||
node.Set("test4", NewNumber("4"))
|
||||
node.Set("test5", NewNumber("5"))
|
||||
n := NewNull()
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
node.Set("test3", n)
|
||||
|
|
@ -996,7 +986,6 @@ func BenchmarkMapSet(b *testing.B) {
|
|||
node.Set("test5", NewNumber("5"))
|
||||
m, _ := node.Map()
|
||||
n := NewNull()
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
m["test3"] = n
|
||||
|
|
@ -1015,7 +1004,6 @@ func BenchmarkNodeSetByIndex(b *testing.B) {
|
|||
node.Add(NewNumber("4"))
|
||||
node.Add(NewNumber("5"))
|
||||
n := NewNull()
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
node.SetByIndex(2, n)
|
||||
|
|
@ -1035,7 +1023,6 @@ func BenchmarkSliceSetByIndex(b *testing.B) {
|
|||
node.Add(NewNumber("5"))
|
||||
m, _ := node.Array()
|
||||
n := NewNull()
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
m[2] = n
|
||||
|
|
@ -1069,7 +1056,6 @@ func BenchmarkNodeUnset(b *testing.B) {
|
|||
node.Set("test3", NewNumber("3"))
|
||||
node.Set("test4", NewNumber("4"))
|
||||
node.Set("test5", NewNumber("5"))
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
node.Unset("test3")
|
||||
|
|
@ -1088,7 +1074,6 @@ func BenchmarkMapUnset(b *testing.B) {
|
|||
node.Set("test4", NewNumber("4"))
|
||||
node.Set("test5", NewNumber("5"))
|
||||
m, _ := node.Map()
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
delete(m, "test3")
|
||||
|
|
@ -1106,7 +1091,6 @@ func BenchmarkNodUnsetByIndex(b *testing.B) {
|
|||
node.Add(NewNumber("3"))
|
||||
node.Add(NewNumber("4"))
|
||||
node.Add(NewNumber("5"))
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
node.UnsetByIndex(2)
|
||||
|
|
@ -1125,7 +1109,6 @@ func BenchmarkSliceUnsetByIndex(b *testing.B) {
|
|||
node.Add(NewNumber("4"))
|
||||
node.Add(NewNumber("5"))
|
||||
m, _ := node.Array()
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for i:=3; i<5; i++ {
|
||||
|
|
@ -1136,7 +1119,6 @@ func BenchmarkSliceUnsetByIndex(b *testing.B) {
|
|||
|
||||
func BenchmarkNodeAdd(b *testing.B) {
|
||||
n := NewObject([]Pair{{"test", NewNumber("1")}})
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
node := NewArray([]Node{})
|
||||
|
|
@ -1146,7 +1128,6 @@ func BenchmarkNodeAdd(b *testing.B) {
|
|||
|
||||
func BenchmarkSliceAdd(b *testing.B) {
|
||||
n := NewObject([]Pair{{"test", NewNumber("1")}})
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
node := []Node{}
|
||||
|
|
@ -1156,7 +1137,6 @@ func BenchmarkSliceAdd(b *testing.B) {
|
|||
|
||||
func BenchmarkMapAdd(b *testing.B) {
|
||||
n := NewObject([]Pair{{"test", NewNumber("1")}})
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
node := map[string]Node{}
|
||||
|
|
|
|||
|
|
@ -240,52 +240,95 @@ func TestParsehNotExist(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkParser_StdLib(b *testing.B) {
|
||||
var bv = []byte(_TwitterJson)
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var out interface{}
|
||||
_ = json.Unmarshal(bv, &out)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParser_JsonIter(b *testing.B) {
|
||||
var bv = []byte(_TwitterJson)
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var out interface{}
|
||||
_ = jsoniter.Unmarshal(bv, &out)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParser_Sonic(b *testing.B) {
|
||||
_, _, _ = Loads(_TwitterJson)
|
||||
r, err := NewParser(_TwitterJson).Parse()
|
||||
if err != 0 {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if err := r.LoadAll(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _, _ = Loads(_TwitterJson)
|
||||
r, _ = NewParser(_TwitterJson).Parse()
|
||||
_ = r.LoadAll()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParser_Parallel_StdLib(b *testing.B) {
|
||||
var bv = []byte(_TwitterJson)
|
||||
func BenchmarkParser_Gjson(b *testing.B) {
|
||||
gjson.Parse(_TwitterJson).ForEach(func(key, value gjson.Result) bool {
|
||||
if !value.Exists() {
|
||||
b.Fatal(value.Index)
|
||||
}
|
||||
_ = value.Value()
|
||||
return true
|
||||
})
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
gjson.Parse(_TwitterJson).ForEach(func(key, value gjson.Result) bool {
|
||||
if !value.Exists() {
|
||||
b.Fatal(value.Index)
|
||||
}
|
||||
_ = value.Value()
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParser_Jsoniter(b *testing.B) {
|
||||
v := jsoniter.Get([]byte(_TwitterJson)).GetInterface()
|
||||
if v == nil {
|
||||
b.Fatal(v)
|
||||
}
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = jsoniter.Get([]byte(_TwitterJson)).GetInterface()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParser_Parallel_Sonic(b *testing.B) {
|
||||
r, _ := NewParser(_TwitterJson).Parse()
|
||||
if err := r.LoadAll(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
var out interface{}
|
||||
_ = json.Unmarshal(bv, &out)
|
||||
r, _ := NewParser(_TwitterJson).Parse()
|
||||
_ = r.LoadAll()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkParser_Parallel_JsonIter(b *testing.B) {
|
||||
func BenchmarkParser_Parallel_Gjson(b *testing.B) {
|
||||
gjson.Parse(_TwitterJson).ForEach(func(key, value gjson.Result) bool {
|
||||
if !value.Exists() {
|
||||
b.Fatal(value.Index)
|
||||
}
|
||||
return true
|
||||
})
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
gjson.Parse(_TwitterJson).ForEach(func(key, value gjson.Result) bool {
|
||||
if !value.Exists() {
|
||||
b.Fatal(value.Index)
|
||||
}
|
||||
_ = value.Value()
|
||||
return true
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkParser_Parallel_Jsoniter(b *testing.B) {
|
||||
var bv = []byte(_TwitterJson)
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
|
|
@ -295,98 +338,215 @@ func BenchmarkParser_Parallel_JsonIter(b *testing.B) {
|
|||
})
|
||||
}
|
||||
|
||||
func BenchmarkParser_Parallel_Sonic(b *testing.B) {
|
||||
_, _, _ = Loads(_TwitterJson)
|
||||
func BenchmarkParseOne_Sonic(b *testing.B) {
|
||||
ast, _ := NewParser(_TwitterJson).Parse()
|
||||
node, _ := ast.Get("statuses").Index(2).Get("id").Int64()
|
||||
if node != 249289491129438208 {
|
||||
b.Fail()
|
||||
}
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ast, _ := NewParser(_TwitterJson).Parse()
|
||||
_, _ = ast.Get("statuses").Index(2).Get("id").Int64()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParseOne_Gjson(b *testing.B) {
|
||||
ast := gjson.Parse(_TwitterJson)
|
||||
node := ast.Get("statuses.2.id")
|
||||
v := node.Int()
|
||||
if v != 249289491129438208 {
|
||||
b.Fatal(node)
|
||||
}
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ast := gjson.Parse(_TwitterJson)
|
||||
node := ast.Get("statuses.2.id")
|
||||
_ = node.Int()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParseOne_Jsoniter(b *testing.B) {
|
||||
data := []byte(_TwitterJson)
|
||||
ast := jsoniter.Get(data, "statuses", 2, "id")
|
||||
node := ast.ToInt()
|
||||
if node != 249289491129438208 {
|
||||
b.Fail()
|
||||
}
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ast := jsoniter.Get(data, "statuses", 2, "id")
|
||||
_ = ast.ToInt()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParseOne_Parallel_Sonic(b *testing.B) {
|
||||
ast, _ := NewParser(_TwitterJson).Parse()
|
||||
node, _ := ast.Get("statuses").Index(2).Get("id").Int64()
|
||||
if node != 249289491129438208 {
|
||||
b.Fail()
|
||||
}
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.SetParallelism(parallelism)
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_, _, _ = Loads(_TwitterJson)
|
||||
ast, _ := NewParser(_TwitterJson).Parse()
|
||||
_, _ = ast.Get("statuses").Index(2).Get("id").Int64()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkGetOne_Gjson(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
ast := gjson.Get(_TwitterJson, "statuses.2.id")
|
||||
node := ast.Int()
|
||||
if node != 249289491129438208 {
|
||||
b.Fatal(node)
|
||||
}
|
||||
func BenchmarkParseOne_Parallel_Gjson(b *testing.B) {
|
||||
ast := gjson.Parse(_TwitterJson)
|
||||
node := ast.Get("statuses.2.id")
|
||||
v := node.Int()
|
||||
if v != 249289491129438208 {
|
||||
b.Fatal(node)
|
||||
}
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
ast := gjson.Parse(_TwitterJson)
|
||||
node := ast.Get("statuses.2.id")
|
||||
_ = node.Int()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkGetOne_Jsoniter(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
func BenchmarkParseOne_Parallel_Jsoniter(b *testing.B) {
|
||||
data := []byte(_TwitterJson)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ast := jsoniter.Get(data, "statuses", 2, "id")
|
||||
node := ast.ToInt()
|
||||
if node != 249289491129438208 {
|
||||
b.Fail()
|
||||
}
|
||||
ast := jsoniter.Get(data, "statuses", 2, "id")
|
||||
node := ast.ToInt()
|
||||
if node != 249289491129438208 {
|
||||
b.Fail()
|
||||
}
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
data := []byte(_TwitterJson)
|
||||
ast := jsoniter.Get(data, "statuses", 2, "id")
|
||||
_ = ast.ToInt()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkGetOne_Sonic(b *testing.B) {
|
||||
func BenchmarkParseSeven_Sonic(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ast, _ := NewParser(_TwitterJson).Parse()
|
||||
node, _ := ast.Get("statuses").Index(2).Get("id").Int64()
|
||||
if node != 249289491129438208 {
|
||||
b.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGetSeven_Gjson(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
ast := gjson.Get(_TwitterJson, "statuses.3.id")
|
||||
ast = gjson.Get(_TwitterJson, "statuses.3.user.entities.description")
|
||||
ast = gjson.Get(_TwitterJson, "statuses.3.user.entities.url.urls")
|
||||
ast = gjson.Get(_TwitterJson, "statuses.3.user.entities.url")
|
||||
ast = gjson.Get(_TwitterJson, "statuses.3.user.created_at")
|
||||
ast = gjson.Get(_TwitterJson, "statuses.3.user.name")
|
||||
ast = gjson.Get(_TwitterJson, "statuses.3.text")
|
||||
if ast.Value() == nil {
|
||||
b.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGetSeven_Jsoniter(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
data := []byte(_TwitterJson)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ast := jsoniter.Get(data, "statuses", 3, "id")
|
||||
ast = jsoniter.Get(data, "statuses", 3, "user", "entities","description")
|
||||
ast = jsoniter.Get(data, "statuses", 3, "user", "entities","url","urls")
|
||||
ast = jsoniter.Get(data, "statuses", 3, "user", "entities","url")
|
||||
ast = jsoniter.Get(data, "statuses", 3, "user", "created_at")
|
||||
ast = jsoniter.Get(data, "statuses", 3, "user", "name")
|
||||
ast = jsoniter.Get(data, "statuses", 3, "text")
|
||||
if ast == nil {
|
||||
b.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGetSeven_SonicParser(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
ast, _ := NewParser(_TwitterJson).Parse()
|
||||
node := ast.GetByPath( "statuses", 3, "id")
|
||||
node := ast.GetByPath("statuses", 3, "id")
|
||||
node = ast.GetByPath("statuses", 3, "user", "entities","description")
|
||||
node = ast.GetByPath("statuses", 3, "user", "entities","url","urls")
|
||||
node = ast.GetByPath("statuses", 3, "user", "entities","url","urls")
|
||||
node = ast.GetByPath("statuses", 3, "user", "entities","url")
|
||||
node = ast.GetByPath("statuses", 3, "user", "created_at")
|
||||
node = ast.GetByPath("statuses", 3, "user", "name")
|
||||
node = ast.GetByPath("statuses", 3, "text")
|
||||
if node == nil {
|
||||
if node.Check() != nil {
|
||||
b.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParseSeven_Gjson(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ast := gjson.Parse(_TwitterJson)
|
||||
node := ast.Get("statuses.3.id")
|
||||
node = ast.Get( "statuses.3.user.entities.description")
|
||||
node = ast.Get( "statuses.3.user.entities.url.urls")
|
||||
node = ast.Get( "statuses.3.user.entities.url")
|
||||
node = ast.Get( "statuses.3.user.created_at")
|
||||
node = ast.Get( "statuses.3.user.name")
|
||||
node = ast.Get( "statuses.3.text")
|
||||
if node.Value() == nil {
|
||||
b.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParseSeven_Jsoniter(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
data := []byte(_TwitterJson)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ast := jsoniter.Get(data)
|
||||
node := ast.Get("statuses", 3, "id")
|
||||
node = ast.Get("statuses", 3, "user", "entities","description")
|
||||
node = ast.Get("statuses", 3, "user", "entities","url","urls")
|
||||
node = ast.Get("statuses", 3, "user", "entities","url")
|
||||
node = ast.Get("statuses", 3, "user", "created_at")
|
||||
node = ast.Get("statuses", 3, "user", "name")
|
||||
node = ast.Get("statuses", 3, "text")
|
||||
if node.LastError() != nil {
|
||||
b.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParseSeven_Parallel_Sonic(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
ast, _ := NewParser(_TwitterJson).Parse()
|
||||
node := ast.GetByPath("statuses", 3, "id")
|
||||
node = ast.GetByPath("statuses", 3, "user", "entities","description")
|
||||
node = ast.GetByPath("statuses", 3, "user", "entities","url","urls")
|
||||
node = ast.GetByPath("statuses", 3, "user", "entities","url")
|
||||
node = ast.GetByPath("statuses", 3, "user", "created_at")
|
||||
node = ast.GetByPath("statuses", 3, "user", "name")
|
||||
node = ast.GetByPath("statuses", 3, "text")
|
||||
if node.Check() != nil {
|
||||
b.Fail()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkParseSeven_Parallel_Gjson(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
ast := gjson.Parse(_TwitterJson)
|
||||
node := ast.Get("statuses.3.id")
|
||||
node = ast.Get( "statuses.3.user.entities.description")
|
||||
node = ast.Get( "statuses.3.user.entities.url.urls")
|
||||
node = ast.Get( "statuses.3.user.entities.url")
|
||||
node = ast.Get( "statuses.3.user.created_at")
|
||||
node = ast.Get( "statuses.3.user.name")
|
||||
node = ast.Get( "statuses.3.text")
|
||||
if node.Value() == nil {
|
||||
b.Fail()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkParseSeven_Parallel_Jsoniter(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
data := []byte(_TwitterJson)
|
||||
ast := jsoniter.Get(data)
|
||||
node := ast.Get("statuses", 3, "id")
|
||||
node = ast.Get("statuses", 3, "user", "entities","description")
|
||||
node = ast.Get("statuses", 3, "user", "entities","url","urls")
|
||||
node = ast.Get("statuses", 3, "user", "entities","url")
|
||||
node = ast.Get("statuses", 3, "user", "created_at")
|
||||
node = ast.Get("statuses", 3, "user", "name")
|
||||
node = ast.Get("statuses", 3, "text")
|
||||
if node.LastError() != nil {
|
||||
b.Fail()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,11 @@ import (
|
|||
`runtime`
|
||||
`runtime/debug`
|
||||
`sync`
|
||||
`fmt`
|
||||
`math`
|
||||
`strconv`
|
||||
|
||||
`github.com/tidwall/sjson`
|
||||
jsoniter `github.com/json-iterator/go`
|
||||
`github.com/stretchr/testify/assert`
|
||||
`github.com/tidwall/gjson`
|
||||
|
|
@ -190,7 +194,7 @@ func TestSearchNotExist(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkSearchOne_Gjson(b *testing.B) {
|
||||
func BenchmarkGetOne_Gjson(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
ast := gjson.Get(_TwitterJson, "statuses.3.id")
|
||||
|
|
@ -201,7 +205,7 @@ func BenchmarkSearchOne_Gjson(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkSearchOne_Jsoniter(b *testing.B) {
|
||||
func BenchmarkGetOne_Jsoniter(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
data := []byte(_TwitterJson)
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
|
@ -213,7 +217,7 @@ func BenchmarkSearchOne_Jsoniter(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkSearchOne_Sonic(b *testing.B) {
|
||||
func BenchmarkGetOne_Sonic(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
ast := NewSearcher(_TwitterJson)
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
|
@ -228,9 +232,8 @@ func BenchmarkSearchOne_Sonic(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkSearchOne_Parallel_Gjson(b *testing.B) {
|
||||
func BenchmarkGetOne_Parallel_Gjson(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.SetParallelism(parallelism)
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
ast := gjson.Get(_TwitterJson, "statuses.3.id")
|
||||
|
|
@ -242,10 +245,9 @@ func BenchmarkSearchOne_Parallel_Gjson(b *testing.B) {
|
|||
})
|
||||
}
|
||||
|
||||
func BenchmarkSearchOne_Parallel_Jsoniter(b *testing.B) {
|
||||
func BenchmarkGetOne_Parallel_Jsoniter(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
data := []byte(_TwitterJson)
|
||||
b.SetParallelism(parallelism)
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
ast := jsoniter.Get(data, "statuses", 3, "id")
|
||||
|
|
@ -257,9 +259,8 @@ func BenchmarkSearchOne_Parallel_Jsoniter(b *testing.B) {
|
|||
})
|
||||
}
|
||||
|
||||
func BenchmarkSearchOne_Parallel_Sonic(b *testing.B) {
|
||||
func BenchmarkGetOne_Parallel_Sonic(b *testing.B) {
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.SetParallelism(parallelism)
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
ast := NewSearcher(_TwitterJson)
|
||||
for pb.Next() {
|
||||
|
|
@ -274,3 +275,107 @@ func BenchmarkSearchOne_Parallel_Sonic(b *testing.B) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkSetOne_Sonic(b *testing.B) {
|
||||
node, err := NewSearcher(_TwitterJson).GetByPath("statuses", 3)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
n := NewNumber(strconv.Itoa(math.MaxInt32))
|
||||
_, err = node.Set("id", n)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
node, _ := NewSearcher(_TwitterJson).GetByPath("statuses", 3)
|
||||
_, _ = node.Set("id", n)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSetOne_Sjson(b *testing.B) {
|
||||
path := fmt.Sprintf("%s.%d.%s", "statuses", 3, "id")
|
||||
_, err := sjson.Set(_TwitterJson, path, math.MaxInt32)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
sjson.Set(_TwitterJson, path, math.MaxInt32)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSetOne_Jsoniter(b *testing.B) {
|
||||
data := []byte(_TwitterJson)
|
||||
node, ok := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{})
|
||||
if !ok {
|
||||
b.Fatal(node)
|
||||
}
|
||||
|
||||
b.SetBytes(int64(len(data)))
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
node, _ := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{})
|
||||
node["id"] = math.MaxInt32
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSetOne_Parallel_Sonic(b *testing.B) {
|
||||
node, err := NewSearcher(_TwitterJson).GetByPath("statuses", 3)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
n := NewNumber(strconv.Itoa(math.MaxInt32))
|
||||
_, err = node.Set("id", n)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
node, _ := NewSearcher(_TwitterJson).GetByPath("statuses", 3)
|
||||
_, _ = node.Set("id", n)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkSetOne_Parallel_Sjson(b *testing.B) {
|
||||
path := fmt.Sprintf("%s.%d.%s", "statuses", 3, "id")
|
||||
_, err := sjson.Set(_TwitterJson, path, math.MaxInt32)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.SetBytes(int64(len(_TwitterJson)))
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
sjson.Set(_TwitterJson, path, math.MaxInt32)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkSetOne_Parallel_Jsoniter(b *testing.B) {
|
||||
data := []byte(_TwitterJson)
|
||||
node, ok := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{})
|
||||
if !ok {
|
||||
b.Fatal(node)
|
||||
}
|
||||
|
||||
b.SetBytes(int64(len(data)))
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
node, _ := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{})
|
||||
node["id"] = math.MaxInt32
|
||||
}
|
||||
})
|
||||
}
|
||||
BIN
bench-large.jpg
Normal file
BIN
bench-large.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 362 KiB |
BIN
bench-large.png
BIN
bench-large.png
Binary file not shown.
|
Before Width: | Height: | Size: 96 KiB |
BIN
bench-small.jpg
Normal file
BIN
bench-small.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 390 KiB |
BIN
bench-small.png
BIN
bench-small.png
Binary file not shown.
|
Before Width: | Height: | Size: 93 KiB |
6
bench.sh
6
bench.sh
|
|
@ -10,11 +10,11 @@ cd $pwd/decoder
|
|||
go test -benchmem -run=^$ -benchtime=100000x -bench "^(BenchmarkDecoder_Generic_Sonic|BenchmarkDecoder_Generic_StdLib|BenchmarkDecoder_Generic_JsonIter|BenchmarkDecoder_Generic_GoJson|BenchmarkDecoder_Binding_Sonic|BenchmarkDecoder_Binding_StdLib|BenchmarkDecoder_Binding_JsonIter|BenchmarkDecoder_Binding_GoJson|BenchmarkDecoder_Parallel_Generic_Sonic|BenchmarkDecoder_Parallel_Generic_StdLib|BenchmarkDecoder_Parallel_Generic_JsonIter|BenchmarkDecoder_Parallel_Generic_GoJson|BenchmarkDecoder_Parallel_Binding_Sonic|BenchmarkDecoder_Parallel_Binding_StdLib|BenchmarkDecoder_Parallel_Binding_JsonIter|BenchmarkDecoder_Parallel_Binding_GoJson)$"
|
||||
|
||||
cd $pwd/ast
|
||||
go test -benchmem -run=^$ -benchtime=100000x -bench "^(BenchmarkSearchOne_Gjson|BenchmarkSearchOne_Jsoniter|BenchmarkSearchOne_Sonic|BenchmarkSearchOne_Parallel_Gjson|BenchmarkSearchOne_Parallel_Jsoniter|BenchmarkSearchOne_Parallel_Sonic)$"
|
||||
go test -benchmem -run=^$ -benchtime=10000x -bench "^(BenchmarkParser_StdLib|BenchmarkParser_JsonIter|BenchmarkParser_Sonic|BenchmarkParser_Parallel_StdLib|BenchmarkParser_Parallel_JsonIter|BenchmarkParser_Parallel_Sonic|BenchmarkGetOne_Gjson|BenchmarkGetOne_Jsoniter|BenchmarkGetOne_Sonic|BenchmarkGetSeven_Gjson|BenchmarkGetSeven_Jsoniter|BenchmarkGetSeven_SonicParser)$"
|
||||
go test -benchmem -run=^$ -benchtime=100000x -bench "^(BenchmarkGetOne_Sonic|BenchmarkGetOne_Gjson|BenchmarkGetOne_Jsoniter|BenchmarkGetOne_Parallel_Sonic|BenchmarkGetOne_Parallel_Gjson|BenchmarkGetOne_Parallel_Jsoniter|BenchmarkSetOne_Sonic|BenchmarkSetOne_Sjson|BenchmarkSetOne_Jsoniter|BenchmarkSetOne_Parallel_Sonic|BenchmarkSetOne_Parallel_Sjson|BenchmarkSetOne_Parallel_Jsoniter)$"
|
||||
go test -benchmem -run=^$ -benchtime=10000x -bench "^(BenchmarkParser_Sonic|BenchmarkParser_Gjson|BenchmarkParser_JsonIter|BenchmarkParser_Parallel_Sonic|BenchmarkParser_Parallel_Gjson|BenchmarkParser_Parallel_StdLib|BenchmarkParser_Parallel_JsonIter|BenchmarkParseOne_Sonic|BenchmarkParseOne_Gjson|BenchmarkParseOne_Jsoniter|BenchmarkParseOne_Parallel_Sonic|BenchmarkParseOne_Parallel_Gjson|BenchmarkParseOne_Parallel_Jsoniter|BenchmarkParseSeven_Sonic|BenchmarkParseSeven_Gjson|BenchmarkParseSeven_Jsoniter|BenchmarkParseSeven_Parallel_Sonic|BenchmarkParseSeven_Parallel_Gjson|BenchmarkParseSeven_Parallel_Jsoniter)$"
|
||||
go test -benchmem -run=^$ -benchtime=100000x -bench '^(BenchmarkEncodeRaw|BenchmarkEncodeSkip|BenchmarkEncodeLoad)$'
|
||||
|
||||
go test -benchmem -run=^$ -benchtime=10000000x -bench "^(BenchmarkNodeGetByPath|BenchmarkStructGetByPath_Jsoniter|BenchmarkNodeIndex|BenchmarkStructIndex|BenchmarkSliceIndex|BenchmarkMapIndex|BenchmarkNodeGet|BenchmarkSliceGet|BenchmarkMapGet|BenchmarkNodeSet|BenchmarkMapSet|BenchmarkNodeSetByIndex|BenchmarkSliceSetByIndex|BenchmarkStructSetByIndex|BenchmarkNodeUnset|BenchmarkMapUnset|BenchmarkNodUnsetByIndex|BenchmarkSliceUnsetByIndex|BenchmarkNodeAdd|BenchmarkSliceAdd|BenchmarkMapAdd)$"
|
||||
go test -benchmem -run=^$ -benchtime=10000000x -bench "^(BenchmarkNodeGetByPath|BenchmarkStructGetByPath|BenchmarkNodeIndex|BenchmarkStructIndex|BenchmarkSliceIndex|BenchmarkMapIndex|BenchmarkNodeGet|BenchmarkSliceGet|BenchmarkMapGet|BenchmarkNodeSet|BenchmarkMapSet|BenchmarkNodeSetByIndex|BenchmarkSliceSetByIndex|BenchmarkStructSetByIndex|BenchmarkNodeUnset|BenchmarkMapUnset|BenchmarkNodUnsetByIndex|BenchmarkSliceUnsetByIndex|BenchmarkNodeAdd|BenchmarkSliceAdd|BenchmarkMapAdd)$"
|
||||
|
||||
unset SONIC_NO_ASYNC_GC
|
||||
cd $pwd
|
||||
|
|
@ -122,8 +122,6 @@ func Pretouch(vt reflect.Type, opts ...option.CompileOption) error {
|
|||
func pretouchType(_vt reflect.Type, opts option.CompileOptions) (map[reflect.Type]bool, error) {
|
||||
/* compile function */
|
||||
compiler := newCompiler().apply(opts)
|
||||
|
||||
/* compile function */
|
||||
decoder := func(vt *rt.GoType) (interface{}, error) {
|
||||
if pp, err := compiler.compile(_vt); err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
3
go.mod
3
go.mod
|
|
@ -9,6 +9,7 @@ require (
|
|||
github.com/json-iterator/go v1.1.10
|
||||
github.com/klauspost/cpuid/v2 v2.0.9
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/tidwall/gjson v1.8.0
|
||||
github.com/tidwall/gjson v1.10.2
|
||||
github.com/tidwall/sjson v1.2.3
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1
|
||||
)
|
||||
|
|
|
|||
16
go.sum
16
go.sum
|
|
@ -1,4 +1,3 @@
|
|||
github.com/chenzhuoyu/base64x v0.0.0-20210823082418-56861234f7ea/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06 h1:1sDoSuDPWzhkdzNVxCxtIaKiAe96ESVPv8coGwc1gZ4=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
|
@ -17,17 +16,18 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLD
|
|||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tidwall/gjson v1.8.0 h1:Qt+orfosKn0rbNTZqHYDqBrmm3UDA4KRkv70fDzG+PQ=
|
||||
github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
|
||||
github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
|
||||
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8=
|
||||
github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/gjson v1.10.2 h1:APbLGOM0rrEkd8WBw9C24nllro4ajFuJu0Sc9hRz8Bo=
|
||||
github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.3 h1:5+deguEhHSEjmuICXZ21uSSsXotWMA0orU783+Z7Cp8=
|
||||
github.com/tidwall/sjson v1.2.3/go.mod h1:5WdjKx3AQMvCJ4RG6/2UYT7dLrGvJUV1x4jdTAyGvZs=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
|
|
|
|||
Loading…
Reference in a new issue