easyjson icon indicating copy to clipboard operation
easyjson copied to clipboard

Question: Why using easyjson structs for Marshal with encoding/json is so inefficient?

Open crisperit opened this issue 4 years ago • 1 comments

Hey - I've tried to benchmark your library in terms of its cooperation with encoding/json

tl;dr; Using easy json generated struct for Marshal (with encoding/json) is much worse than using the same struct without easy json generated code.

BenchmarkMarshalEasyJsonWithEncoding-8       	  124141	      9555 ns/op	    3126 B/op	       8 allocs/op
BenchmarkUnmarshalEasyJsonWithEncoding-8     	  103888	     11387 ns/op	     976 B/op	      31 allocs/op
BenchmarkMarshalNormalJsonWithEncoding-8     	  397566	      2988 ns/op	    1472 B/op	       2 allocs/op
BenchmarkUnmarshalNormalJsonWithEncoding-8   	  102706	     12116 ns/op	     992 B/op	      32 allocs/op

So my thought was that most of libraries are using encoding/json underneath - so if I can generate efficient MarshalJSON and UnmarshalJSON implementations for my structs I can get boost up in the performance

Sadly in mine test the results were different and I would like to know why

Structs used in test:

//easyjson:json
type EasyJsonStruct struct {
	Field1  string   `json:"field1,omitempty"`
	Field2  string   `json:"field2,omitempty"`
	Field3  []string `json:"field3,omitempty"`
	Field4  string   `json:"field4,omitempty"`
	Field5  string   `json:"field5,omitempty"`
	Field6  string   `json:"field6,omitempty"`
	Field7  *int8    `json:"field7,omitempty"`
	Field8  *bool    `json:"field8,omitempty"`
	Field9  *bool    `json:"field9,omitempty"`
	Field10 string   `json:"field10,omitempty"`
	Field11 string   `json:"field11,omitempty"`
	Field12 string   `json:"field12,omitempty"`
	Field13 string   `json:"field13,omitempty"`
	Field14 string   `json:"field14,omitempty"`
	Field15 []string `json:"field15,omitempty"`
	Field16 *bool    `json:"field16,omitempty"`
	Field17 string   `json:"field17,omitempty"`
	Field18 string   `json:"field18,omitempty"`
	Field19 string   `json:"field19,omitempty"`
	Field20 string   `json:"field20,omitempty"`
	Field21 string   `json:"field21,omitempty"`
	Field22 string   `json:"field22,omitempty"`
	Field23 string   `json:"field23,omitempty"`
	Field24 []string `json:"field24,omitempty"`
	Field25 []string `json:"field25,omitempty"`
	Field26 []string `json:"field26,omitempty"`
	Field27 string   `json:"field27,omitempty"`
}

//easyjson:skip
type JsonStruct struct {
	Field1  string   `json:"field1,omitempty"`
	Field2  string   `json:"field2,omitempty"`
	Field3  []string `json:"field3,omitempty"`
	Field4  string   `json:"field4,omitempty"`
	Field5  string   `json:"field5,omitempty"`
	Field6  string   `json:"field6,omitempty"`
	Field7  *int8    `json:"field7,omitempty"`
	Field8  *bool    `json:"field8,omitempty"`
	Field9  *bool    `json:"field9,omitempty"`
	Field10 string   `json:"field10,omitempty"`
	Field11 string   `json:"field11,omitempty"`
	Field12 string   `json:"field12,omitempty"`
	Field13 string   `json:"field13,omitempty"`
	Field14 string   `json:"field14,omitempty"`
	Field15 []string `json:"field15,omitempty"`
	Field16 *bool    `json:"field16,omitempty"`
	Field17 string   `json:"field17,omitempty"`
	Field18 string   `json:"field18,omitempty"`
	Field19 string   `json:"field19,omitempty"`
	Field20 string   `json:"field20,omitempty"`
	Field21 string   `json:"field21,omitempty"`
	Field22 string   `json:"field22,omitempty"`
	Field23 string   `json:"field23,omitempty"`
	Field24 []string `json:"field24,omitempty"`
	Field25 []string `json:"field25,omitempty"`
	Field26 []string `json:"field26,omitempty"`
	Field27 string   `json:"field27,omitempty"`
}

The test:

package main

import (
	"encoding/json"
	"testing"
)

var jsonStruct JsonStruct
var jsonStructBytes []byte
var easyJsonStruct EasyJsonStruct
var easyJsonStructBytes []byte

func init() {
	testBool := true
	testInt8 := int8(1)

	jsonStruct = JsonStruct{
		Field1:  "testData121453vvczcsdwdgw",
		Field2:  "testData121453vvczcsdwdgw",
		Field3:  []string{"testData121453vvczcsdwdgw", "fsadfdsf"},
		Field4:  "testData121453vvczcsdwdgw",
		Field5:  "testData121453vvczcsdwdgw",
		Field6:  "testData121453vvczcsdwdgw",
		Field7:  &testInt8,
		Field8:  &testBool,
		Field9:  &testBool,
		Field10: "testData121453vvczcsdwdgw",
		Field11: "testData121453vvczcsdwdgw",
		Field12: "testData121453vvczcsdwdgw",
		Field13: "testData121453vvczcsdwdgw",
		Field14: "testData121453vvczcsdwdgw",
		Field15: []string{"testData121453vvczcsdwdgw", "fsadfdsf"},
		Field16: &testBool,
		Field17: "testData121453vvczcsdwdgw",
		Field18: "testData121453vvczcsdwdgw",
		Field19: "testData121453vvczcsdwdgw",
		Field20: "testData121453vvczcsdwdgw",
		Field21: "testData121453vvczcsdwdgw",
		Field22: "testData121453vvczcsdwdgw",
		Field23: "testData121453vvczcsdwdgw",
		Field24: []string{"testData121453vvczcsdwdgw", "fsadfdsf"},
		Field25: []string{"testData121453vvczcsdwdgw", "fsadfdsf"},
		Field26: []string{"testData121453vvczcsdwdgw", "fsadfdsf"},
		Field27: "testData121453vvczcsdwdgw",
	}
	easyJsonStruct = EasyJsonStruct{
		Field1:  "testData121453vvczcsdwdgw",
		Field2:  "testData121453vvczcsdwdgw",
		Field3:  []string{"testData121453vvczcsdwdgw", "fsadfdsf"},
		Field4:  "testData121453vvczcsdwdgw",
		Field5:  "testData121453vvczcsdwdgw",
		Field6:  "testData121453vvczcsdwdgw",
		Field7:  &testInt8,
		Field8:  &testBool,
		Field9:  &testBool,
		Field10: "testData121453vvczcsdwdgw",
		Field11: "testData121453vvczcsdwdgw",
		Field12: "testData121453vvczcsdwdgw",
		Field13: "testData121453vvczcsdwdgw",
		Field14: "testData121453vvczcsdwdgw",
		Field15: []string{"testData121453vvczcsdwdgw", "fsadfdsf"},
		Field16: &testBool,
		Field17: "testData121453vvczcsdwdgw",
		Field18: "testData121453vvczcsdwdgw",
		Field19: "testData121453vvczcsdwdgw",
		Field20: "testData121453vvczcsdwdgw",
		Field21: "testData121453vvczcsdwdgw",
		Field22: "testData121453vvczcsdwdgw",
		Field23: "testData121453vvczcsdwdgw",
		Field24: []string{"testData121453vvczcsdwdgw", "fsadfdsf"},
		Field25: []string{"testData121453vvczcsdwdgw", "fsadfdsf"},
		Field26: []string{"testData121453vvczcsdwdgw", "fsadfdsf"},
		Field27: "testData121453vvczcsdwdgw",
	}
	easyJsonStructBytes, _ = json.Marshal(easyJsonStruct)
	jsonStructBytes, _ = json.Marshal(jsonStruct)
}

func BenchmarkMarshalEasyJsonWithEncoding(b *testing.B) {
	b.ReportAllocs()
	for n := 0; n < b.N; n++ {
		_, _ = json.Marshal(easyJsonStruct)
	}
}

func BenchmarkUnmarshalEasyJsonWithEncoding(b *testing.B) {
	var obj EasyJsonStruct
	b.ReportAllocs()
	for n := 0; n < b.N; n++ {
		_ = json.Unmarshal(easyJsonStructBytes, &obj)
	}
}

func BenchmarkMarshalNormalJsonWithEncoding(b *testing.B) {
	b.ReportAllocs()
	for n := 0; n < b.N; n++ {
		_, _ = json.Marshal(jsonStruct)
	}
}

func BenchmarkUnmarshalNormalJsonWithEncoding(b *testing.B) {
	var obj JsonStruct
	b.ReportAllocs()
	for n := 0; n < b.N; n++ {
		_ = json.Unmarshal(jsonStructBytes, &obj)
	}
}

crisperit avatar Aug 04 '21 09:08 crisperit

easyJson must be generate xxx_easyjson.go, and call generate file.

lpflpf avatar Aug 09 '21 04:08 lpflpf