From 6e0babc7e842e3080bdc53d94084167e2ac8db65 Mon Sep 17 00:00:00 2001 From: Josh Baker Date: Fri, 14 Apr 2017 11:13:32 -0700 Subject: [PATCH] updated benchmarks, added features list --- README.md | 37 +++++++++--------- gjson_test.go | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 35d4724..4898423 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,14 @@ src="logo.png" width="240" height="78" border="0" alt="GJSON">
-Build Status +Build Status GoDoc

get a json value quickly

-GJSON is a Go package that provides a [fast](#performance) and [simple](#get-a-value) way to get values from a json document with one line of code. +GJSON is a Go package that provides a [fast](#performance) and [simple](#get-a-value) way to get values from a json document. +It has features such as [one line retrieval](#get-a-value), [dot notation paths](#path-syntax), [iteration](#iterate-through-an-object-or-array), and [map unmarshalling](#unmarshal-to-a-map). Getting Started =============== @@ -283,26 +282,28 @@ The return value is a `[]Result`, which will always contain exactly the same num Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/), [ffjson](https://github.com/pquerna/ffjson), [EasyJSON](https://github.com/mailru/easyjson), -and [jsonparser](https://github.com/buger/jsonparser) +[jsonparser](https://github.com/buger/jsonparser), +and [json-iterator](https://github.com/json-iterator/go) ``` -BenchmarkGJSONGet-8 15000000 333 ns/op 0 B/op 0 allocs/op -BenchmarkGJSONUnmarshalMap-8 900000 4188 ns/op 1920 B/op 26 allocs/op -BenchmarkJSONUnmarshalMap-8 600000 8908 ns/op 3048 B/op 69 allocs/op -BenchmarkJSONUnmarshalStruct-8 600000 9026 ns/op 1832 B/op 69 allocs/op -BenchmarkJSONDecoder-8 300000 14339 ns/op 4224 B/op 184 allocs/op -BenchmarkFFJSONLexer-8 1500000 3156 ns/op 896 B/op 8 allocs/op -BenchmarkEasyJSONLexer-8 3000000 938 ns/op 613 B/op 6 allocs/op -BenchmarkJSONParserGet-8 3000000 442 ns/op 21 B/op 0 allocs/op +BenchmarkGJSONGet-8 3000000 372 ns/op 0 B/op 0 allocs/op +BenchmarkGJSONUnmarshalMap-8 900000 4154 ns/op 1920 B/op 26 allocs/op +BenchmarkJSONUnmarshalMap-8 600000 9019 ns/op 3048 B/op 69 allocs/op +BenchmarkJSONUnmarshalStruct-8 600000 9268 ns/op 1832 B/op 69 allocs/op +BenchmarkJSONDecoder-8 300000 14120 ns/op 4224 B/op 184 allocs/op +BenchmarkFFJSONLexer-8 1500000 3111 ns/op 896 B/op 8 allocs/op +BenchmarkEasyJSONLexer-8 3000000 887 ns/op 613 B/op 6 allocs/op +BenchmarkJSONParserGet-8 3000000 499 ns/op 21 B/op 0 allocs/op +BenchmarkJSONIterator-8 3000000 812 ns/op 544 B/op 9 allocs/op ``` Benchmarks for the `GetMany` function: ``` -BenchmarkGJSONGetMany4Paths-8 4000000 319 ns/op 112 B/op 0 allocs/op -BenchmarkGJSONGetMany8Paths-8 8000000 218 ns/op 56 B/op 0 allocs/op -BenchmarkGJSONGetMany16Paths-8 16000000 160 ns/op 56 B/op 0 allocs/op -BenchmarkGJSONGetMany32Paths-8 32000000 130 ns/op 64 B/op 0 allocs/op +BenchmarkGJSONGetMany4Paths-8 4000000 303 ns/op 112 B/op 0 allocs/op +BenchmarkGJSONGetMany8Paths-8 8000000 208 ns/op 56 B/op 0 allocs/op +BenchmarkGJSONGetMany16Paths-8 16000000 156 ns/op 56 B/op 0 allocs/op +BenchmarkGJSONGetMany32Paths-8 32000000 127 ns/op 64 B/op 0 allocs/op BenchmarkGJSONGetMany64Paths-8 64000000 117 ns/op 64 B/op 0 allocs/op BenchmarkGJSONGetMany128Paths-8 128000000 109 ns/op 64 B/op 0 allocs/op ``` @@ -360,7 +361,7 @@ widget.text.data widget.text.size ``` -*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.7.* +*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.8.* ## Contact Josh Baker [@tidwall](http://twitter.com/tidwall) diff --git a/gjson_test.go b/gjson_test.go index 062b30a..08901d8 100644 --- a/gjson_test.go +++ b/gjson_test.go @@ -12,6 +12,7 @@ import ( "time" "github.com/buger/jsonparser" + jsoniter "github.com/json-iterator/go" "github.com/mailru/easyjson/jlexer" fflib "github.com/pquerna/ffjson/fflib/v1" ) @@ -1163,6 +1164,106 @@ func BenchmarkJSONParserGet(t *testing.B) { } t.N *= len(benchPaths) // because we are running against 3 paths } +func jsoniterWindowName(t *testing.B, iter *jsoniter.Iterator) { + var v string + for { + key := iter.ReadObject() + if key != "window" { + iter.Skip() + continue + } + for { + key := iter.ReadObject() + if key != "name" { + iter.Skip() + continue + } + v = iter.ReadString() + break + } + break + } + if v == "" { + t.Fatal("did not find the value") + } +} + +func jsoniterTextOnMouseUp(t *testing.B, iter *jsoniter.Iterator) { + var v string + for { + key := iter.ReadObject() + if key != "text" { + iter.Skip() + continue + } + for { + key := iter.ReadObject() + if key != "onMouseUp" { + iter.Skip() + continue + } + v = iter.ReadString() + break + } + break + } + if v == "" { + t.Fatal("did not find the value") + } +} +func jsoniterImageOffset(t *testing.B, iter *jsoniter.Iterator) { + var v int + for { + key := iter.ReadObject() + if key != "image" { + iter.Skip() + continue + } + for { + key := iter.ReadObject() + if key != "hOffset" { + iter.Skip() + continue + } + v = iter.ReadInt() + break + } + break + } + if v == 0 { + t.Fatal("did not find the value") + } +} +func jsoniterWidget(t *testing.B, iter *jsoniter.Iterator, j int) { + for { + key := iter.ReadObject() + if key != "widget" { + iter.Skip() + continue + } + switch benchPaths[j] { + case "widget.window.name": + jsoniterWindowName(t, iter) + case "widget.image.hOffset": + jsoniterImageOffset(t, iter) + case "widget.text.onMouseUp": + jsoniterTextOnMouseUp(t, iter) + } + break + } +} + +func BenchmarkJSONIterator(t *testing.B) { + t.ReportAllocs() + t.ResetTimer() + for i := 0; i < t.N; i++ { + for j := 0; j < len(benchPaths); j++ { + iter := jsoniter.ParseString(exampleJSON) + jsoniterWidget(t, iter, j) + } + } + t.N *= len(benchPaths) // because we are running against 3 paths +} var massiveJSON = func() string { var buf bytes.Buffer