Skip to content

Instantly share code, notes, and snippets.

@tidwall
Created September 3, 2022 17:44
Show Gist options
  • Save tidwall/d05bd07649e10740b011eda68acff75d to your computer and use it in GitHub Desktop.
Save tidwall/d05bd07649e10740b011eda68acff75d to your computer and use it in GitHub Desktop.
Easyjson vs gjson for structured data
package gjsonvseasy
import (
"testing"
"github.com/mailru/easyjson"
"github.com/tidwall/gjson"
)
var bytes = []byte(`{"s": "BENCHTEST", "b": 57.654321, "a": 117.123456, "m": 10000000, "mb": 10000000, "p": 12.737993485790131, "pb": 12.739859708664888, "t": 1655299719123, "i": 9, "d": 5, "fi": 2, "qs": true, "ts": true}`)
var result SampleJSON
func BenchmarkEasyjson(b *testing.B) {
var decodedData SampleJSON
for i := 0; i < b.N; i++ {
if err := easyjson.Unmarshal(bytes, &decodedData); err != nil {
b.Fatal(err)
}
}
result = decodedData
}
func BenchmarkGjsonCheck(b *testing.B) {
var decodedData SampleJSON
for i := 0; i < b.N; i++ {
res := gjson.GetBytes(bytes, "s")
if res.Type == gjson.Null {
b.Fatal("`s` not found")
}
decodedData.S = res.String()
res = gjson.GetBytes(bytes, "i")
if res.Type == gjson.Null {
b.Fatal("`i` not found")
}
decodedData.I = int(res.Int())
res = gjson.GetBytes(bytes, "b")
if res.Type == gjson.Null {
b.Fatal("`b` not found")
}
decodedData.B = res.Float()
res = gjson.GetBytes(bytes, "a")
if res.Type == gjson.Null {
b.Fatal("`a` not found")
}
decodedData.A = res.Float()
res = gjson.GetBytes(bytes, "m")
if res.Type == gjson.Null {
b.Fatal("`m` not found")
}
decodedData.M = res.Float()
res = gjson.GetBytes(bytes, "mb")
if res.Type == gjson.Null {
b.Fatal("`mb` not found")
}
decodedData.MB = res.Float()
res = gjson.GetBytes(bytes, "p")
if res.Type == gjson.Null {
b.Fatal("`p` not found")
}
decodedData.P = res.Float()
res = gjson.GetBytes(bytes, "pb")
if res.Type == gjson.Null {
b.Fatal("`pb` not found")
}
decodedData.PB = res.Float()
res = gjson.GetBytes(bytes, "t")
if res.Type == gjson.Null {
b.Fatal("`t` not found")
}
decodedData.T = res.Int()
res = gjson.GetBytes(bytes, "d")
if res.Type == gjson.Null {
b.Fatal("`d` not found")
}
decodedData.D = int(res.Int())
res = gjson.GetBytes(bytes, "fi")
if res.Type == gjson.Null {
b.Fatal("`fi` not found")
}
decodedData.FI = int(res.Int())
res = gjson.GetBytes(bytes, "qs")
if res.Type == gjson.Null {
b.Fatal("`qs` not found")
}
decodedData.QS = res.Bool()
res = gjson.GetBytes(bytes, "ts")
if res.Type == gjson.Null {
b.Fatal("`ts` not found")
}
decodedData.TS = res.Bool()
}
result = decodedData
}
func BenchmarkGjsonNoCheck(b *testing.B) {
var decodedData SampleJSON
for i := 0; i < b.N; i++ {
decodedData.S = gjson.GetBytes(bytes, "s").String()
decodedData.I = int(gjson.GetBytes(bytes, "i").Int())
decodedData.B = gjson.GetBytes(bytes, "b").Float()
decodedData.A = gjson.GetBytes(bytes, "a").Float()
decodedData.M = gjson.GetBytes(bytes, "m").Float()
decodedData.MB = gjson.GetBytes(bytes, "mb").Float()
decodedData.P = gjson.GetBytes(bytes, "p").Float()
decodedData.PB = gjson.GetBytes(bytes, "pb").Float()
decodedData.T = gjson.GetBytes(bytes, "t").Int()
decodedData.D = int(gjson.GetBytes(bytes, "d").Int())
decodedData.FI = int(gjson.GetBytes(bytes, "fi").Int())
decodedData.QS = gjson.GetBytes(bytes, "qs").Bool()
decodedData.TS = gjson.GetBytes(bytes, "ts").Bool()
}
result = decodedData
}
func BenchmarkGjsonMany(b *testing.B) {
var decodedData SampleJSON
paths := []string{"s", "i", "b", "a", "m", "mb", "p", "pb", "t", "d", "fi", "qs", "ts"}
for i := 0; i < b.N; i++ {
results := gjson.GetManyBytes(bytes, paths...)
decodedData.S = results[0].String()
decodedData.I = int(results[1].Int())
decodedData.B = results[2].Float()
decodedData.A = results[3].Float()
decodedData.M = results[4].Float()
decodedData.MB = results[5].Float()
decodedData.P = results[6].Float()
decodedData.PB = results[7].Float()
decodedData.T = results[8].Int()
decodedData.D = int(results[9].Int())
decodedData.FI = int(results[10].Int())
decodedData.QS = results[11].Bool()
decodedData.TS = results[12].Bool()
}
result = decodedData
}
func BenchmarkGjsonCheckString(b *testing.B) {
var decodedData SampleJSON
str := string(bytes)
for i := 0; i < b.N; i++ {
res := gjson.Get(str, "s")
if res.Type == gjson.Null {
b.Fatal("`s` not found")
}
decodedData.S = res.String()
res = gjson.Get(str, "i")
if res.Type == gjson.Null {
b.Fatal("`i` not found")
}
decodedData.I = int(res.Int())
res = gjson.Get(str, "b")
if res.Type == gjson.Null {
b.Fatal("`b` not found")
}
decodedData.B = res.Float()
res = gjson.Get(str, "a")
if res.Type == gjson.Null {
b.Fatal("`a` not found")
}
decodedData.A = res.Float()
res = gjson.Get(str, "m")
if res.Type == gjson.Null {
b.Fatal("`m` not found")
}
decodedData.M = res.Float()
res = gjson.Get(str, "mb")
if res.Type == gjson.Null {
b.Fatal("`mb` not found")
}
decodedData.MB = res.Float()
res = gjson.Get(str, "p")
if res.Type == gjson.Null {
b.Fatal("`p` not found")
}
decodedData.P = res.Float()
res = gjson.Get(str, "pb")
if res.Type == gjson.Null {
b.Fatal("`pb` not found")
}
decodedData.PB = res.Float()
res = gjson.Get(str, "t")
if res.Type == gjson.Null {
b.Fatal("`t` not found")
}
decodedData.T = res.Int()
res = gjson.Get(str, "d")
if res.Type == gjson.Null {
b.Fatal("`d` not found")
}
decodedData.D = int(res.Int())
res = gjson.Get(str, "fi")
if res.Type == gjson.Null {
b.Fatal("`fi` not found")
}
decodedData.FI = int(res.Int())
res = gjson.Get(str, "qs")
if res.Type == gjson.Null {
b.Fatal("`qs` not found")
}
decodedData.QS = res.Bool()
res = gjson.Get(str, "ts")
if res.Type == gjson.Null {
b.Fatal("`ts` not found")
}
decodedData.TS = res.Bool()
}
result = decodedData
}
func BenchmarkGjsonNoCheckString(b *testing.B) {
var decodedData SampleJSON
str := string(bytes)
for i := 0; i < b.N; i++ {
decodedData.S = gjson.Get(str, "s").String()
decodedData.I = int(gjson.Get(str, "i").Int())
decodedData.B = gjson.Get(str, "b").Float()
decodedData.A = gjson.Get(str, "a").Float()
decodedData.M = gjson.Get(str, "m").Float()
decodedData.MB = gjson.Get(str, "mb").Float()
decodedData.P = gjson.Get(str, "p").Float()
decodedData.PB = gjson.Get(str, "pb").Float()
decodedData.T = gjson.Get(str, "t").Int()
decodedData.D = int(gjson.Get(str, "d").Int())
decodedData.FI = int(gjson.Get(str, "fi").Int())
decodedData.QS = gjson.Get(str, "qs").Bool()
decodedData.TS = gjson.Get(str, "ts").Bool()
}
result = decodedData
}
func BenchmarkGjsonForEach(b *testing.B) {
var decodedData SampleJSON
str := string(bytes)
for i := 0; i < b.N; i++ {
gjson.Parse(str).ForEach(func(k, v gjson.Result) bool {
switch k.String() {
case "s":
decodedData.S = v.String()
case "i":
decodedData.I = int(v.Int())
case "b":
decodedData.B = v.Float()
case "a":
decodedData.A = v.Float()
case "m":
decodedData.M = v.Float()
case "mb":
decodedData.MB = v.Float()
case "p":
decodedData.P = v.Float()
case "pb":
decodedData.PB = v.Float()
case "t":
decodedData.T = v.Int()
case "d":
decodedData.D = int(v.Int())
case "fi":
decodedData.FI = int(v.Int())
case "qs":
decodedData.QS = v.Bool()
case "ts":
decodedData.TS = v.Bool()
}
return true
})
}
result = decodedData
}
@tidwall
Copy link
Author

tidwall commented Sep 3, 2022

goos: darwin
goarch: arm64
pkg: example.com/gjsonvseasy
BenchmarkEasyjson-10              	 1549269	       762.6 ns/op	      16 B/op	       1 allocs/op
BenchmarkGjsonCheck-10            	  471752	      2526 ns/op	     136 B/op	      10 allocs/op
BenchmarkGjsonNoCheck-10          	  475734	      2524 ns/op	     136 B/op	      10 allocs/op
BenchmarkGjsonMany-10             	  421005	      2752 ns/op	    1288 B/op	      11 allocs/op
BenchmarkGjsonCheckString-10      	  540081	      2163 ns/op	       0 B/op	       0 allocs/op
BenchmarkGjsonNoCheckString-10    	  551227	      2169 ns/op	       0 B/op	       0 allocs/op
BenchmarkGjsonForEach-10          	 1421556	       846.6 ns/op	       0 B/op	       0 allocs/op

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment