Skip to content

Instantly share code, notes, and snippets.

@evalphobia
Last active February 22, 2024 18:28
Show Gist options
  • Save evalphobia/a2ba2636acbc112f68dcd89e8b81d349 to your computer and use it in GitHub Desktop.
Save evalphobia/a2ba2636acbc112f68dcd89e8b81d349 to your computer and use it in GitHub Desktop.
Golang Benchmark: gob vs json

tl;dr

  • JSON is faster for small size data
    • map (key size < 50 and Unmarshalling intensive workload)
    • single struct
  • gob is faster for big size data
    • map (key size > 50 or Marshalling intensive workload)
    • slice

(old) about

benchmark result to encode/decode map[int64]float64

Since Go1.7 encoding/json package supports map[int64]float64. So I tried to check the encoding perfomance of both old gob version and new json version, and if json version is better then I replace it from gob.

results on 2022-07-19

# running on MacBook Pro (13-inch, M1, 2020)
$ go version
go version go1.18 darwin/amd64

map

map[int64]float64
$ go test -bench 'codeMap$' -benchmem

BenchmarkEncodeMap/algo=Gob:key=10-8         	  597687	      1779 ns/op	    1328 B/op	      36 allocs/op
BenchmarkEncodeMap/algo=JSON:key=10-8        	  530013	      2210 ns/op	    1128 B/op	      26 allocs/op
BenchmarkEncodeMap/algo=Gob:key=50-8         	  250100	      4646 ns/op	    2704 B/op	     119 allocs/op
BenchmarkEncodeMap/algo=JSON:key=50-8        	   96696	     12215 ns/op	    4649 B/op	     106 allocs/op
BenchmarkEncodeMap/algo=Gob:key=100-8        	  141145	      8510 ns/op	    4304 B/op	     220 allocs/op
BenchmarkEncodeMap/algo=JSON:key=100-8       	   46933	     25888 ns/op	    9291 B/op	     206 allocs/op
BenchmarkEncodeMap/algo=Gob:key=1000-8       	   15400	     77591 ns/op	   48784 B/op	    2027 allocs/op
BenchmarkEncodeMap/algo=JSON:key=1000-8      	    3639	    324308 ns/op	   99284 B/op	    2906 allocs/op

BenchmarkDecodeMap/algo=Gob:key=10-8         	   91844	     12609 ns/op	    7085 B/op	     177 allocs/op
BenchmarkDecodeMap/algo=JSON:key=10-8        	  401668	      2894 ns/op	     732 B/op	      17 allocs/op
BenchmarkDecodeMap/algo=Gob:key=50-8         	   72354	     16710 ns/op	    8369 B/op	     181 allocs/op
BenchmarkDecodeMap/algo=JSON:key=50-8        	   78045	     15519 ns/op	    3518 B/op	     146 allocs/op
BenchmarkDecodeMap/algo=Gob:key=100-8        	   54596	     22115 ns/op	   10134 B/op	     182 allocs/op
BenchmarkDecodeMap/algo=JSON:key=100-8       	   39087	     31064 ns/op	    7246 B/op	     302 allocs/op
BenchmarkDecodeMap/algo=Gob:key=1000-8       	   10000	    109675 ns/op	   54626 B/op	     182 allocs/op
BenchmarkDecodeMap/algo=JSON:key=1000-8      	    3486	    355120 ns/op	  108780 B/op	    3794 allocs/op

slice map

[]map[int64]float64
$ go test -bench 'codeSliceMap$' -benchmem

BenchmarkEncodeSliceMap/algo=Gob:key=10:len=10-8         	  127593	      9561 ns/op	    5352 B/op     230 allocs/op
BenchmarkEncodeSliceMap/algo=JSON:key=10:len=10-8        	   55711	     21273 ns/op	   11308 B/op     252 allocs/op
BenchmarkEncodeSliceMap/algo=Gob:key=10:len=1000-8       	    1534	    784413 ns/op	  484300 B/op   21034 allocs/op
BenchmarkEncodeSliceMap/algo=JSON:key=10:len=1000-8      	     552	   2174333 ns/op	 1133415 B/op   25006 allocs/op
BenchmarkEncodeSliceMap/algo=Gob:key=100:len=10-8        	    1596	    754511 ns/op	  434603 B/op   20134 allocs/op
BenchmarkEncodeSliceMap/algo=JSON:key=100:len=10-8       	     457	   2582626 ns/op	  928522 B/op   20503 allocs/op
BenchmarkEncodeSliceMap/algo=Gob:key=1000:len=10-8       	      14	  82473330 ns/op	56088296 B/op 2001054 allocs/op
BenchmarkEncodeSliceMap/algo=JSON:key=1000:len=10-8      	       4	 316158510 ns/op	107563562 B/op 2905010 allocs/op

BenchmarkDecodeSliceMap/algo=Gob:key=10:len=10-8         	   49984	     23680 ns/op	   12323 B/op     243 allocs/op
BenchmarkDecodeSliceMap/algo=JSON:key=10:len=10-8        	   40273	     29571 ns/op	    6282 B/op     152 allocs/op
BenchmarkDecodeSliceMap/algo=Gob:key=10:len=1000-8       	    1020	   1161246 ns/op	  540420 B/op    6267 allocs/op
BenchmarkDecodeSliceMap/algo=JSON:key=10:len=1000-8      	     420	   2850912 ns/op	  600485 B/op   14119 allocs/op
BenchmarkDecodeSliceMap/algo=Gob:key=100:len=10-8        	    1066	   1064541 ns/op	  367049 B/op    1323 allocs/op
BenchmarkDecodeSliceMap/algo=JSON:key=100:len=10-8       	     366	   3254086 ns/op	  712260 B/op   29960 allocs/op
BenchmarkDecodeSliceMap/algo=Gob:key=1000:len=10-8       	      12	  95134396 ns/op	48005190 B/op   11557 allocs/op
BenchmarkDecodeSliceMap/algo=JSON:key=1000:len=10-8      	       3	 333699458 ns/op	108656554 B/op 3791294 allocs/op

single struct

type SmallStruct struct {
	ID   int64  `json:"id"`
	Name string `json:"name"`
}

type MediumStruct struct {
	ID        int64     `json:"id"`
	Name      string    `json:"name"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
	Field1    string    `json:"field1"`
	Field2    *string   `json:"field2"`
	Field3    *string   `json:"field3"`
	Field4    float64   `json:"field4"`

	SmallStruct SmallStruct `json:"small_struct"`
}

type BigStruct struct {
	ID        int64     `json:"id"`
	Name      string    `json:"name"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
	Field1    string    `json:"field1"`
	Field2    *string   `json:"field2"`
	Field3    *string   `json:"field3"`
	Field4    float64   `json:"field4"`

	MediumStruct1 MediumStruct  `json:"medium_struct_1"`
	MediumStruct2 MediumStruct  `json:"medium_struct_2"`
	MediumStruct3 *MediumStruct `json:"medium_struct_3"`
}
$ go test -bench 'SingleStruct$' -benchmem

BenchmarkEncodeSingleStruct/algo=Gob:struct_size=small-8         	  806529	      1322 ns/op	    1136 B/op	      20 allocs/op
BenchmarkEncodeSingleStruct/algo=JSON:struct_size=small-8        	 8575928	       135.4 ns/op	      24 B/op	       1 allocs/op
BenchmarkEncodeSingleStruct/algo=Gob:struct_size=medium-8        	  278229	      4069 ns/op	    2056 B/op	      44 allocs/op
BenchmarkEncodeSingleStruct/algo=JSON:struct_size=medium-8       	 1000000	      1049 ns/op	     288 B/op	       3 allocs/op
BenchmarkEncodeSingleStruct/algo=Gob:struct_size=big-8           	  161725	      7250 ns/op	    3128 B/op	      67 allocs/op
BenchmarkEncodeSingleStruct/algo=JSON:struct_size=big-8          	  294415	      3907 ns/op	    1152 B/op	       9 allocs/op

BenchmarkDecodeSingleStruct/algo=Gob:struct_size=small-8         	  102616	     11573 ns/op	    6760 B/op	     179 allocs/op
BenchmarkDecodeSingleStruct/algo=JSON:struct_size=small-8        	 2272239	       521.9 ns/op	     248 B/op	       6 allocs/op
BenchmarkDecodeSingleStruct/algo=Gob:struct_size=medium-8        	   69972	     16868 ns/op	    9108 B/op	     253 allocs/op
BenchmarkDecodeSingleStruct/algo=JSON:struct_size=medium-8       	  450344	      2628 ns/op	     496 B/op	      13 allocs/op
BenchmarkDecodeSingleStruct/algo=Gob:struct_size=big-8           	   51835	     23132 ns/op	   12037 B/op	     341 allocs/op
BenchmarkDecodeSingleStruct/algo=JSON:struct_size=big-8          	  119002	     10143 ns/op	    1216 B/op	      29 allocs/op

slice struct

[]SmallStruct
[]MediumStruct
[]BigStruct
$ go test -bench 'SliceStruct$' -benchmem

BenchmarkEncodeSliceStruct/algo=Gob:struct_size=small:len=100-8         	  142580	      7949 ns/op	    5488 B/op	      26 allocs/op
BenchmarkEncodeSliceStruct/algo=JSON:struct_size=small:len=100-8        	  176148	      6937 ns/op	    2689 B/op	       1 allocs/op
BenchmarkEncodeSliceStruct/algo=Gob:struct_size=medium:len=100-8        	   38203	     32148 ns/op	   13368 B/op	      50 allocs/op
BenchmarkEncodeSliceStruct/algo=JSON:struct_size=medium:len=100-8       	    9904	    115569 ns/op	   28692 B/op	     201 allocs/op
BenchmarkEncodeSliceStruct/algo=Gob:struct_size=big:len=100-8           	   10000	    109469 ns/op	   46280 B/op	      78 allocs/op
BenchmarkEncodeSliceStruct/algo=JSON:struct_size=big:len=100-8          	    2666	    463901 ns/op	  120469 B/op	     801 allocs/op

BenchmarkDecodeSliceStruct/algo=Gob:struct_size=small:len=100-8         	   56674	     19855 ns/op	   11564 B/op	     298 allocs/op
BenchmarkDecodeSliceStruct/algo=JSON:struct_size=small:len=100-8        	   22933	     52902 ns/op	   11544 B/op	     216 allocs/op
BenchmarkDecodeSliceStruct/algo=Gob:struct_size=medium:len=100-8        	   28304	     40497 ns/op	   30269 B/op	     669 allocs/op
BenchmarkDecodeSliceStruct/algo=JSON:struct_size=medium:len=100-8       	    3642	    326436 ns/op	   70040 B/op	     808 allocs/op
BenchmarkDecodeSliceStruct/algo=Gob:struct_size=big:len=100-8           	   10000	    100115 ns/op	   85303 B/op	    1550 allocs/op
BenchmarkDecodeSliceStruct/algo=JSON:struct_size=big:len=100-8          	     922	   1281704 ns/op	  222266 B/op	    2299 allocs/op

slice pointer struct

[]*SmallStruct
[]*MediumStruct
[]*BigStruct
$ go test -bench 'SliceStructPointer$' -benchmem

BenchmarkEncodeSliceStructPointer/algo=Gob:struct_size=small:len=100-8         	  132654	      8567 ns/op	    5488 B/op	      26 allocs/op
BenchmarkEncodeSliceStructPointer/algo=JSON:struct_size=small:len=100-8        	  152977	      7456 ns/op	    2689 B/op	       1 allocs/op
BenchmarkEncodeSliceStructPointer/algo=Gob:struct_size=medium:len=100-8        	   38146	     31688 ns/op	   13336 B/op	      50 allocs/op
BenchmarkEncodeSliceStructPointer/algo=JSON:struct_size=medium:len=100-8       	   10000	    101825 ns/op	   28697 B/op	     201 allocs/op
BenchmarkEncodeSliceStructPointer/algo=Gob:struct_size=big:len=100-8           	   10000	    109204 ns/op	   46216 B/op	      78 allocs/op
BenchmarkEncodeSliceStructPointer/algo=JSON:struct_size=big:len=100-8          	    2904	    402087 ns/op	  120464 B/op	     801 allocs/op

BenchmarkDecodeSliceStructPointer/algo=Gob:struct_size=small:len=100-8         	   47467	     24451 ns/op	   12140 B/op	     397 allocs/op
BenchmarkDecodeSliceStructPointer/algo=JSON:struct_size=small:len=100-8        	   25448	     47057 ns/op	    7096 B/op	     316 allocs/op
BenchmarkDecodeSliceStructPointer/algo=Gob:struct_size=medium:len=100-8        	   26494	     45081 ns/op	   31197 B/op	     767 allocs/op
BenchmarkDecodeSliceStructPointer/algo=JSON:struct_size=medium:len=100-8       	    4441	    373324 ns/op	   26888 B/op	     908 allocs/op
BenchmarkDecodeSliceStructPointer/algo=Gob:struct_size=big:len=100-8           	   10152	    105312 ns/op	   86790 B/op	    1647 allocs/op
BenchmarkDecodeSliceStructPointer/algo=JSON:struct_size=big:len=100-8          	    1136	   1039947 ns/op	   88873 B/op	    2399 allocs/op
package main
import (
"bytes"
"encoding/gob"
"encoding/json"
)
func createMap(keySize int) map[int64]float64 {
m := make(map[int64]float64)
for i := 0; i < keySize; i++ {
m[int64(i)] = float64(i)
}
return m
}
func createSliceMap(keySize, lenSize int) []map[int64]float64 {
list := make([]map[int64]float64, lenSize)
for i := 0; i < lenSize; i++ {
list[i] = createMap(keySize)
}
return list
}
func encodeGob(v interface{}) []byte {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err := enc.Encode(v)
if err != nil {
panic(err)
}
return buf.Bytes()
}
func decodeGob(b []byte, result interface{}) {
buf := bytes.NewBuffer(b)
enc := gob.NewDecoder(buf)
err := enc.Decode(result)
if err != nil {
panic(err)
}
}
func encodeJSON(v interface{}) []byte {
byt, err := json.Marshal(v)
if err != nil {
panic(err)
}
return byt
}
func decodeJSON(b []byte, result interface{}) {
err := json.Unmarshal(b, result)
if err != nil {
panic(err)
}
}
package main
import "testing"
func BenchmarkEncodeMap(b *testing.B) {
benchmarks := []struct {
name string
keySize int
fn func(interface{}) []byte
}{
{"algo=Gob:key=10", 10, encodeGob},
{"algo=JSON:key=10", 10, encodeJSON},
{"algo=Gob:key=50", 50, encodeGob},
{"algo=JSON:key=50", 50, encodeJSON},
{"algo=Gob:key=100", 100, encodeGob},
{"algo=JSON:key=100", 100, encodeJSON},
{"algo=Gob:key=1000", 1000, encodeGob},
{"algo=JSON:key=1000", 1000, encodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := createMap(bm.keySize)
b.ResetTimer()
for i := 0; i < b.N; i++ {
res := bm.fn(m)
_ = res
}
})
}
}
func BenchmarkDecodeMap(b *testing.B) {
benchmarks := []struct {
name string
keySize int
encode func(interface{}) []byte
decode func([]byte, interface{})
}{
{"algo=Gob:key=10", 10, encodeGob, decodeGob},
{"algo=JSON:key=10", 10, encodeJSON, decodeJSON},
{"algo=Gob:key=50", 50, encodeGob, decodeGob},
{"algo=JSON:key=50", 50, encodeJSON, decodeJSON},
{"algo=Gob:key=100", 100, encodeGob, decodeGob},
{"algo=JSON:key=100", 100, encodeJSON, decodeJSON},
{"algo=Gob:key=1000", 1000, encodeGob, decodeGob},
{"algo=JSON:key=1000", 1000, encodeJSON, decodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := createMap(bm.keySize)
byt := bm.encode(m)
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result map[int64]float64
bm.decode(byt, &result)
}
})
}
}
func BenchmarkEncodeSliceMap(b *testing.B) {
benchmarks := []struct {
name string
keySize int
lenSize int
fn func(interface{}) []byte
}{
{"algo=Gob:key=10:len=10", 10, 10, encodeGob},
{"algo=JSON:key=10:len=10", 10, 10, encodeJSON},
{"algo=Gob:key=10:len=1000", 10, 1000, encodeGob},
{"algo=JSON:key=10:len=1000", 10, 1000, encodeJSON},
{"algo=Gob:key=100:len=10", 100, 100, encodeGob},
{"algo=JSON:key=100:len=10", 100, 100, encodeJSON},
{"algo=Gob:key=1000:len=10", 1000, 1000, encodeGob},
{"algo=JSON:key=1000:len=10", 1000, 1000, encodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := createSliceMap(bm.keySize, bm.lenSize)
b.ResetTimer()
for i := 0; i < b.N; i++ {
res := bm.fn(m)
_ = res
}
})
}
}
func BenchmarkDecodeSliceMap(b *testing.B) {
benchmarks := []struct {
name string
keySize int
lenSize int
encode func(v interface{}) []byte
decode func([]byte, interface{})
}{
{"algo=Gob:key=10:len=10", 10, 10, encodeGob, decodeGob},
{"algo=JSON:key=10:len=10", 10, 10, encodeJSON, decodeJSON},
{"algo=Gob:key=10:len=1000", 10, 1000, encodeGob, decodeGob},
{"algo=JSON:key=10:len=1000", 10, 1000, encodeJSON, decodeJSON},
{"algo=Gob:key=100:len=10", 100, 100, encodeGob, decodeGob},
{"algo=JSON:key=100:len=10", 100, 100, encodeJSON, decodeJSON},
{"algo=Gob:key=1000:len=10", 1000, 1000, encodeGob, decodeGob},
{"algo=JSON:key=1000:len=10", 1000, 1000, encodeJSON, decodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := createSliceMap(bm.keySize, bm.lenSize)
byt := bm.encode(m)
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result []map[int64]float64
bm.decode(byt, &result)
}
})
}
}
package main
import (
"encoding/gob"
"time"
)
func init() {
gob.Register(SmallStruct{})
gob.Register(MediumStruct{})
gob.Register(BigStruct{})
gob.Register([]SmallStruct{})
gob.Register([]MediumStruct{})
gob.Register([]BigStruct{})
gob.Register([]*SmallStruct{})
gob.Register([]*MediumStruct{})
gob.Register([]*BigStruct{})
}
type SmallStruct struct {
ID int64 `json:"id"`
Name string `json:"name"`
}
func newSmallStruct(id int64) SmallStruct {
return SmallStruct{
ID: id,
Name: "name",
}
}
type MediumStruct struct {
ID int64 `json:"id"`
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Field1 string `json:"field1"`
Field2 *string `json:"field2"`
Field3 *string `json:"field3"`
Field4 float64 `json:"field4"`
SmallStruct SmallStruct `json:"small_struct"`
}
func newMediumStruct(id int64) MediumStruct {
v := "field2"
return MediumStruct{
ID: id,
Name: "name",
Field2: &v,
SmallStruct: newSmallStruct(id),
}
}
type BigStruct struct {
ID int64 `json:"id"`
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Field1 string `json:"field1"`
Field2 *string `json:"field2"`
Field3 *string `json:"field3"`
Field4 float64 `json:"field4"`
MediumStruct1 MediumStruct `json:"medium_struct_1"`
MediumStruct2 MediumStruct `json:"medium_struct_2"`
MediumStruct3 *MediumStruct `json:"medium_struct_3"`
}
func newBigStruct(id int64) BigStruct {
v := "field2"
m := newMediumStruct(3)
return BigStruct{
ID: id,
Name: "name",
Field2: &v,
MediumStruct1: newMediumStruct(id),
MediumStruct3: &m,
}
}
func createSmallStructList(max int) []SmallStruct {
list := make([]SmallStruct, max)
for i := range list {
list[i] = newSmallStruct(int64(i))
}
return list
}
func createSmallStructListPtr(max int) []*SmallStruct {
list := make([]*SmallStruct, max)
for i := range list {
v := newSmallStruct(int64(i))
list[i] = &v
}
return list
}
func createMediumStructList(max int) []MediumStruct {
list := make([]MediumStruct, max)
for i := range list {
list[i] = newMediumStruct(int64(i))
}
return list
}
func createMediumStructListPtr(max int) []*MediumStruct {
list := make([]*MediumStruct, max)
for i := range list {
v := newMediumStruct(int64(i))
list[i] = &v
}
return list
}
func createBigStructList(max int) []BigStruct {
list := make([]BigStruct, max)
for i := range list {
list[i] = newBigStruct(int64(i))
}
return list
}
func createBigStructListPtr(max int) []*BigStruct {
list := make([]*BigStruct, max)
for i := range list {
v := newBigStruct(int64(i))
list[i] = &v
}
return list
}
package main
import "testing"
func BenchmarkEncodeSingleStruct(b *testing.B) {
benchmarks := []struct {
name string
structData interface{}
fn func(interface{}) []byte
}{
{"algo=Gob:struct_size=small", newSmallStruct(1), encodeGob},
{"algo=JSON:struct_size=small", newSmallStruct(1), encodeJSON},
{"algo=Gob:struct_size=medium", newMediumStruct(1), encodeGob},
{"algo=JSON:struct_size=medium", newMediumStruct(1), encodeJSON},
{"algo=Gob:struct_size=big", newBigStruct(1), encodeGob},
{"algo=JSON:struct_size=big", newBigStruct(1), encodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := bm.structData
b.ResetTimer()
for i := 0; i < b.N; i++ {
res := bm.fn(m)
_ = res
}
})
}
}
func BenchmarkDecodeSingleStruct(b *testing.B) {
type benchmark struct {
name string
structData interface{}
encode func(interface{}) []byte
decode func([]byte, interface{})
}
benchmarks := []benchmark{
{"algo=Gob:struct_size=small", newSmallStruct(1), encodeGob, decodeGob},
{"algo=JSON:struct_size=small", newSmallStruct(1), encodeJSON, decodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := bm.structData
byt := bm.encode(m)
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result SmallStruct
bm.decode(byt, &result)
}
})
}
benchmarks = []benchmark{
{"algo=Gob:struct_size=medium", newMediumStruct(1), encodeGob, decodeGob},
{"algo=JSON:struct_size=medium", newMediumStruct(1), encodeJSON, decodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := bm.structData
byt := bm.encode(m)
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result MediumStruct
bm.decode(byt, &result)
}
})
}
benchmarks = []benchmark{
{"algo=Gob:struct_size=big", newBigStruct(1), encodeGob, decodeGob},
{"algo=JSON:struct_size=big", newBigStruct(1), encodeJSON, decodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := bm.structData
byt := bm.encode(m)
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result BigStruct
bm.decode(byt, &result)
}
})
}
}
func BenchmarkEncodeSliceStruct(b *testing.B) {
benchmarks := []struct {
name string
structData interface{}
fn func(interface{}) []byte
}{
{"algo=Gob:struct_size=small:len=100", createSmallStructList(100), encodeGob},
{"algo=JSON:struct_size=small:len=100", createSmallStructList(100), encodeJSON},
{"algo=Gob:struct_size=medium:len=100", createMediumStructList(100), encodeGob},
{"algo=JSON:struct_size=medium:len=100", createMediumStructList(100), encodeJSON},
{"algo=Gob:struct_size=big:len=100", createBigStructList(100), encodeGob},
{"algo=JSON:struct_size=big:len=100", createBigStructList(100), encodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := bm.structData
b.ResetTimer()
for i := 0; i < b.N; i++ {
res := bm.fn(m)
_ = res
}
})
}
}
func BenchmarkDecodeSliceStruct(b *testing.B) {
type benchmark struct {
name string
structData interface{}
encode func(interface{}) []byte
decode func([]byte, interface{})
}
benchmarks := []benchmark{
{"algo=Gob:struct_size=small:len=100", createSmallStructList(100), encodeGob, decodeGob},
{"algo=JSON:struct_size=small:len=100", createSmallStructList(100), encodeJSON, decodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := bm.structData
byt := bm.encode(m)
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result []SmallStruct
bm.decode(byt, &result)
}
})
}
benchmarks = []benchmark{
{"algo=Gob:struct_size=medium:len=100", createMediumStructList(100), encodeGob, decodeGob},
{"algo=JSON:struct_size=medium:len=100", createMediumStructList(100), encodeJSON, decodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := bm.structData
byt := bm.encode(m)
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result []MediumStruct
bm.decode(byt, &result)
}
})
}
benchmarks = []benchmark{
{"algo=Gob:struct_size=big:len=100", createBigStructList(100), encodeGob, decodeGob},
{"algo=JSON:struct_size=big:len=100", createBigStructList(100), encodeJSON, decodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := bm.structData
byt := bm.encode(m)
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result []BigStruct
bm.decode(byt, &result)
}
})
}
}
func BenchmarkEncodeSliceStructPointer(b *testing.B) {
benchmarks := []struct {
name string
structData interface{}
fn func(interface{}) []byte
}{
{"algo=Gob:struct_size=small:len=100", createSmallStructListPtr(100), encodeGob},
{"algo=JSON:struct_size=small:len=100", createSmallStructListPtr(100), encodeJSON},
{"algo=Gob:struct_size=medium:len=100", createMediumStructListPtr(100), encodeGob},
{"algo=JSON:struct_size=medium:len=100", createMediumStructListPtr(100), encodeJSON},
{"algo=Gob:struct_size=big:len=100", createBigStructListPtr(100), encodeGob},
{"algo=JSON:struct_size=big:len=100", createBigStructListPtr(100), encodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := bm.structData
b.ResetTimer()
for i := 0; i < b.N; i++ {
res := bm.fn(m)
_ = res
}
})
}
}
func BenchmarkDecodeSliceStructPointer(b *testing.B) {
type benchmark struct {
name string
structData interface{}
encode func(interface{}) []byte
decode func([]byte, interface{})
}
benchmarks := []benchmark{
{"algo=Gob:struct_size=small:len=100", createSmallStructListPtr(100), encodeGob, decodeGob},
{"algo=JSON:struct_size=small:len=100", createSmallStructListPtr(100), encodeJSON, decodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := bm.structData
byt := bm.encode(m)
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result []*SmallStruct
bm.decode(byt, &result)
}
})
}
benchmarks = []benchmark{
{"algo=Gob:struct_size=medium:len=100", createMediumStructListPtr(100), encodeGob, decodeGob},
{"algo=JSON:struct_size=medium:len=100", createMediumStructListPtr(100), encodeJSON, decodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := bm.structData
byt := bm.encode(m)
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result []*MediumStruct
bm.decode(byt, &result)
}
})
}
benchmarks = []benchmark{
{"algo=Gob:struct_size=big:len=100", createBigStructListPtr(100), encodeGob, decodeGob},
{"algo=JSON:struct_size=big:len=100", createBigStructListPtr(100), encodeJSON, decodeJSON},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
m := bm.structData
byt := bm.encode(m)
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result []*BigStruct
bm.decode(byt, &result)
}
})
}
}
@devplayg
Copy link

Very useful. Thank you for your efforts.

@pavelz
Copy link

pavelz commented Jul 5, 2020

thank you!

@osamaroutemonkey
Copy link

Thank you

@seyedmmousavi
Copy link

I used goccy/go-json and then run bench again. Result shows huge improvement for JSON but it is still 50%~100% behind GOB for both speed and memory usage.

@zcl0621
Copy link

zcl0621 commented Dec 26, 2022

Very useful. Thank you for your efforts.

@agambondan
Copy link

thank you brother

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