Why you should avoid ioutil.ReadAll in Go

Daryl Ng
2 min readFeb 19, 2021

--

When you have an io.Reader , the most common way to read is with ioutil.ReadAll but it is not the best and most efficient way.

So here are three functions to compare the different methods to unmarshal JSON from an io.Reader

  1. With ioutil.ReadAll
func IOUtilReadAll(reader io.Reader) (map[string]interface{}, error) {
var (
m map[string]interface{}
b, _ = ioutil.ReadAll(reader)
)

return m, json.Unmarshal(b, &m)
}

2. With io.Copy

func IOCopy(reader io.Reader) (map[string]interface{}, error) {
var (
m map[string]interface{}
buf bytes.Buffer
_, _ = io.Copy(&buf, reader)
)

return m, json.Unmarshal(buf.Bytes(), &m)
}

3. With json.Decoder

func JsonDecoder(reader io.Reader) (map[string]interface{}, error) {
var m map[string]interface{}

return m, json.NewDecoder(reader).Decode(&m)
}

Now, let’s benchmark them!

var jsonStr = `{"one":"foobar","two":"foobar","three":"foobar","four":"foobar","five":"foobar","six":"foobar","seven":"foobar","eight":"foobar","nine":"foobar","ten":"foobar"}`func BenchmarkJsonDecoder(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
JsonDecoder(strings.NewReader(jsonStr))
}
}

func BenchmarkIOUtilReadAll(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
IOUtilReadAll(strings.NewReader(jsonStr))
}
}

func BenchmarkIOCopy(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
IOCopy(strings.NewReader(jsonStr))
}
}

I am passing strings.NewReader to all three functions to be consistent, although it is not necessary for json.Decoder since it does not drain the io.Reader .

And here are the results…

BenchmarkJsonDecoder
BenchmarkJsonDecoder-8 180230 6741 ns/op 2766 B/op 69 allocs/op
BenchmarkIOUtilReadAll
BenchmarkIOUtilReadAll-8 168019 6928 ns/op 4126 B/op 69 allocs/op
BenchmarkIOCopy
BenchmarkIOCopy-8 158901 6677 ns/op 2286 B/op 69 allocs/op

Boom! Although there are minimal differences in ns/op, B/op is a staggering 2x!

But don’t take my words. If you are using ioutil.ReadAll , run a benchmark and compare the difference. This might just be a small performance improvement in your application and the effort could be better spent elsewhere.

I hope this is helpful. Do clap for me (or rather this article) if you think so.

Do follow me if you have not already done so!

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Responses (1)

Write a response