jscan provides a high-performance zero-allocation JSON iterator for Go. It's not compatible with encoding/json and doesn't provide the usual Marshal/Unmarshal capabilities, instead it focuses on fast and efficient scanning over JSON strings with on-the-fly validation.
https://go.dev/play/p/v-VeiMO2fsJ
package main
import (
"fmt"
"github.com/romshark/jscan"
)
func main() {
j := `{
"s": "value",
"t": true,
"f": false,
"0": null,
"n": -9.123e3,
"o0": {},
"a0": [],
"o": {
"k": "\"v\"",
"a": [
true,
null,
"item",
-67.02e9,
["foo"]
]
},
"a3": [
0,
{
"a3.a3":8
}
]
}`
err := jscan.Scan(jscan.Options{
CachePath: true,
EscapePath: true,
}, j, func(i *jscan.Iterator) (err bool) {
fmt.Printf("| value:\n")
fmt.Printf("| level: %d\n", i.Level)
if k := i.Key(); k != "" {
fmt.Printf("| key: %q\n", i.Key())
}
fmt.Printf("| valueType: %s\n", i.ValueType)
if v := i.Value(); v != "" {
fmt.Printf("| value: %q\n", i.Value())
}
fmt.Printf("| arrayIndex: %d\n", i.ArrayIndex)
fmt.Printf("| path: '%s'\n", i.Path())
return false // No Error, resume scanning
})
if err.IsErr() {
fmt.Printf("ERR: %s\n", err)
return
}
}
The following results were recorded on an Apple M1 Max MBP running macOS 12.1
goos: darwin
goarch: arm64
package | version |
---|---|
github.com/go-faster/jx | v1.0.0 |
github.com/json-iterator/go | v1.1.12 |
github.com/sinhashubham95/jsonic | v1.1.0 |
github.com/tidwall/gjson | v1.14.4 |
github.com/valyala/fastjson | v1.6.4 |
Tiny JSON document ({"x":0}
):
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 46.22 ns/op | 0 B/op | 0 allocs/op |
jsoniter | 85.98 ns/op | 160 B/op | 2 allocs/op |
gofaster-jx | 54.21 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson | 50.17 ns/op | 0 B/op | 0 allocs/op |
jscan_withpath | 61.20 ns/op | 0 B/op | 0 allocs/op |
jsoniter_withpath | 92.64 ns/op | 160 B/op | 2 allocs/op |
gofaster-jx_withpath | 64.24 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson_withpath | 73.10 ns/op | 8 B/op | 1 allocs/op |
Small JSON document (335 bytes):
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 506.7 ns/op | 0 B/op | 0 allocs/op |
jsoniter | 768.7 ns/op | 224 B/op | 12 allocs/op |
gofaster-jx | 561.2 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson | 553.0 ns/op | 0 B/op | 0 allocs/op |
jscan_withpath | 670.7 ns/op | 0 B/op | 0 allocs/op |
jsoniter_withpath | 1091 ns/op | 288 B/op | 21 allocs/op |
gofaster-jx_withpath | 934.6 ns/op | 80 B/op | 13 allocs/op |
valyala-fastjson_withpath | 784.7 ns/op | 88 B/op | 10 allocs/op |
Large JSON document (26.1 MB):
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan/ | 24938751 ns/op | 28 B/op | 0 allocs/op |
jsoniter/ | 54856708 ns/op | 32851643 B/op | 1108519 allocs/op |
gofaster-jx/ | 27957946 ns/op | 30 B/op | 0 allocs/op |
valyala-fastjson/ | 28625101 ns/op | 35 B/op | 0 allocs/op |
jscan_withpath/ | 30114974 ns/op | 33 B/op | 0 allocs/op |
jsoniter_withpath/ | 74731725 ns/op | 55597093 B/op | 1757365 allocs/op |
gofaster-jx_withpath/ | 61522048 ns/op | 51623144 B/op | 1533007 allocs/op |
valyala-fastjson_withpath/ | 37039634 ns/op | 13135410 B/op | 325005 allocs/op |
Array of 1024 integers:
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 20441 ns/op | 0 B/op | 0 allocs/op |
jsoniter | 38419 ns/op | 16528 B/op | 1025 allocs/op |
gofaster-jx | 29924 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson | 21763 ns/op | 0 B/op | 0 allocs/op |
jscan_withpath | 30549 ns/op | 0 B/op | 0 allocs/op |
jsoniter_withpath | 82523 ns/op | 24496 B/op | 2973 allocs/op |
gofaster-jx_withpath | 75776 ns/op | 7970 B/op | 1948 allocs/op |
valyala-fastjson_withpath | 42226 ns/op | 8207 B/op | 1024 allocs/op |
Array of 1024 floating point numbers:
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 19628 ns/op | 0 B/op | 0 allocs/op |
jsoniter | 43730 ns/op | 16528 B/op | 1025 allocs/op |
gofaster-jx | 37036 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson | 21320 ns/op | 6 B/op | 0 allocs/op |
jscan_withpath | 34130 ns/op | 0 B/op | 0 allocs/op |
jsoniter_withpath | 88569 ns/op | 24496 B/op | 2973 allocs/op |
gofaster-jx_withpath | 91708 ns/op | 7970 B/op | 1948 allocs/op |
valyala-fastjson_withpath | 42265 ns/op | 8207 B/op | 1024 allocs/op |
Array of 1024 strings:
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 277372 ns/op | 0 B/op | 0 allocs/op |
jsoniter | 585148 ns/op | 670313 B/op | 1019 allocs/op |
gofaster-jx | 166966 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson | 61301 ns/op | 50 B/op | 0 allocs/op |
jscan_withpath | 287013 ns/op | 0 B/op | 0 allocs/op |
jsoniter_withpath | 629999 ns/op | 678286 B/op | 2967 allocs/op |
gofaster-jx_withpath | 281957 ns/op | 677639 B/op | 2927 allocs/op |
valyala-fastjson_withpath | 80256 ns/op | 8261 B/op | 1024 allocs/op |
Array of 1024 nullable booleans:
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 12308 ns/op | 0 B/op | 0 allocs/op |
jsoniter | 21736 ns/op | 144 B/op | 1 allocs/op |
gofaster-jx | 33209 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson | 10913 ns/op | 0 B/op | 0 allocs/op |
jscan_withpath | 22391 ns/op | 0 B/op | 0 allocs/op |
jsoniter_withpath | 62427 ns/op | 8112 B/op | 1949 allocs/op |
gofaster-jx_withpath | 65697 ns/op | 7970 B/op | 1948 allocs/op |
valyala-fastjson_withpath | 31945 ns/op | 8194 B/op | 1024 allocs/op |
Get by path:
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 229.7 ns/op | 16 B/op | 2 allocs/op |
jsoniter | 815.8 ns/op | 496 B/op | 19 allocs/op |
tidwallgjson | 148.9 ns/op | 16 B/op | 2 allocs/op |
valyalafastjson | 108.9 ns/op | 0 B/op | 0 allocs/op |
sinhashubham95jsonic | 194.1 ns/op | 96 B/op | 1 allocs/op |
Validation:
Tiny
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 35.17 ns/op | 0 B/op | 0 allocs/op |
jsoniter | 45.14 ns/op | 0 B/op | 0 allocs/op |
gofaster-jx | 39.19 ns/op | 0 B/op | 0 allocs/op |
encoding-json | 42.53 ns/op | 0 B/op | 0 allocs/op |
tidwallgjson | 15.85 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson | 19.25 ns/op | 0 B/op | 0 allocs/op |
Small
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 411.0 ns/op | 0 B/op | 0 allocs/op |
jsoniter | 717.3 ns/op | 56 B/op | 7 allocs/op |
gofaster-jx | 392.2 ns/op | 0 B/op | 0 allocs/op |
encoding-json | 904.0 ns/op | 0 B/op | 0 allocs/op |
tidwallgjson | 336.0 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson | 372.0 ns/op | 0 B/op | 0 allocs/op |
Large
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 22007394 ns/op | 23 B/op | 0 allocs/op |
jsoniter | 44151891 ns/op | 13583525 B/op | 644362 allocs/op |
gofaster-jx | 20625554 ns/op | 24 B/op | 0 allocs/op |
encoding-json | 68774883 ns/op | 92 B/op | 0 allocs/op |
tidwallgjson | 27378477 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson | 25695158 ns/op | 0 B/op | 0 allocs/op |
Unwinding Stack
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 2612 ns/op | 0 B/op | 0 allocs/op |
jsoniter | 65817 ns/op | 33149 B/op | 1033 allocs/op |
gofaster-jx | 398530 ns/op | 65687 B/op | 1026 allocs/op |
encoding-json | 5133 ns/op | 24 B/op | 1 allocs/op |
tidwallgjson | 14033 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson | 4876865 ns/op | 52431864 B/op | 4134 allocs/op |
Array of 1024 integers
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 17942 ns/op | 0 B/op | 0 allocs/op |
jsoniter | 21317 ns/op | 0 B/op | 0 allocs/op |
gofaster-jx | 17843 ns/op | 0 B/op | 0 allocs/op |
encoding-json | 33607 ns/op | 0 B/op | 0 allocs/op |
tidwallgjson | 13525 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson | 14741 ns/op | 0 B/op | 0 allocs/op |
Array of 1024 floats
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 12755 ns/op | 0 B/op | 0 allocs/op |
jsoniter | 66119 ns/op | 8755 B/op | 547 allocs/op |
gofaster-jx | 20111 ns/op | 0 B/op | 0 allocs/op |
encoding-json | 35978 ns/op | 0 B/op | 0 allocs/op |
tidwallgjson | 12176 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson | 17346 ns/op | 0 B/op | 0 allocs/op |
Array of 1024 nullable booleans
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 5483 ns/op | 0 B/op | 0 allocs/op |
jsoniter | 16538 ns/op | 0 B/op | 0 allocs/op |
gofaster-jx | 20987 ns/op | 0 B/op | 0 allocs/op |
encoding-json | 20309 ns/op | 0 B/op | 0 allocs/op |
tidwallgjson | 5081 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson | 4891 ns/op | 0 B/op | 0 allocs/op |
Array of 1024 strings
implementation | ns/op | B/op | allocs/op |
---|---|---|---|
jscan | 275319 ns/op | 0 B/op | 0 allocs/op |
jsoniter | 507315 ns/op | 0 B/op | 0 allocs/op |
gofaster-jx | 152812 ns/op | 0 B/op | 0 allocs/op |
encoding-json | 1391323 ns/op | 1 B/op | 0 allocs/op |
tidwallgjson | 501928 ns/op | 0 B/op | 0 allocs/op |
valyala-fastjson | 253798 ns/op | 0 B/op | 0 allocs/op |