DEV Community

Cover image for Go: Efficient Marshalling & Unmarshalling
CodePiper
CodePiper

Posted on

Go: Efficient Marshalling & Unmarshalling

If you like to see the video on this blog, then here is the link of the video: https://www.youtube.com/watch?v=FCID6eezGTU


As a developer it is our day-to-day job converting the data from the byte type (received from the network wire in the form of response) to your API response struct. In this blog we will see how we can do that efficiently and in a optimized manner(consume low CPU and Memory)

I will compare two libraries, SONIC and JSON and will perform the benchmark test for these two libraries and check which is optimal for our use case.

Test Criteria:
The payload is divided into three parts.

  1. Small size struct
  2. Medium size struct
  3. Large size struct
  4. Extra Large size struct

*About the operation: *
It will consist a method which is performing two operations, first marshalling and then unmarshalling.

func MarshallingUnmarshallingJSON(t1 []album) {
    var result []*album
    byteReponse, _ := json.Marshal(t1)
    json.Unmarshal(byteReponse, &result)
}

func MarshallingUnmarshallingSONIC(t1 []album) {
    var result []album
    byteReponse, _ := sonic.Marshal(t1)
    sonic.Unmarshal(byteReponse, &result)
}
Enter fullscreen mode Exit fullscreen mode

Result array size lies in four categories, and the benchmark result is as follows:

func BenchmarkJSON(b *testing.B) {
    // Small, Medium, Large, Extra Large
    var input = []int{10, 50, 100, 400}

    for _, v := range input {
        albums := BuildResponse(v)
        b.Run(fmt.Sprintf("input_size_%d", v), func(b *testing.B) {
            for i := 0; i < b.N; i++ {
                MarshallingUnmarshallingJSON(albums)
            }
        })
    }
}

func BenchmarkSonic(b *testing.B) {
    // Small, Medium, Large, Extra Large
    var input = []int{10, 50, 100, 400}

    for _, v := range input {
        albums := BuildResponse(v)
        b.Run(fmt.Sprintf("input_size_%d", v), func(b *testing.B) {
            for i := 0; i < b.N; i++ {
                MarshallingUnmarshallingSONIC(albums)
            }
        })
    }
}
Enter fullscreen mode Exit fullscreen mode

And the results after benchmark test are as follows:

SONIC

Name Operation ns/op B/op allocs/op
BenchmarkSonic/input_size_10-4 184616 10799 ns/op 3787 B/op 11 allocs/op
BenchmarkSonic/input_size_50-4 39327 31660 ns/op 15188 B/op 12 allocs/op
BenchmarkSonic/input_size_100-4 20794 55688 ns/op 34839 B/op 13 allocs/op
BenchmarkSonic/input_size_400-4 5713 213816 ns/op 130859 B/op 14 allocs/op

JSON

Name Operation ns/op B/op allocs/op
BenchmarkJSON/input_size_10-4 21874 57925 ns/op 2689 B/op 57 allocs/op
BenchmarkJSON/input_size_50-4 4152 273070 ns/op 12053 B/op 265 allocs/op
BenchmarkJSON/input_size_100-4 2942 390126 ns/op 24157 B/op 519 allocs/op
BenchmarkJSON/input_size_400-4 930 1406397 ns/op 96853 B/op 2025 allocs/op

In all dimensions, SONIC is the clear winner and recommended for the use as it saves your memory and CPU.

Youtube Channel: https://www.youtube.com/@codepiper

Top comments (3)

Collapse
 
marcello_h profile image
Marcelloh

try this:
github.com/sugawarayuuta/sonnet

Collapse
 
codepiper profile image
CodePiper

Will do the profiling for this library, thanks man

Collapse
 
marcello_h profile image
Marcelloh

Keep us posted of your findings, makes an interesting read :-)