Sitemap

Why you should like sync.Pool?

2 min readApr 18, 2019

Because it’s fast . x4982 reducing memory usage and repository with benchmarks below.

Comparing pool performance. Less than better.

Ok. What the hell?

The garbage collector runs at regular intervals. In case your code constantly allocates memory in some data structures and then frees them, this requires constant work of the collector, more memory and cpu usage for allocating resources on init structs.

The comments on sync/pool.go  say that:A Pool is a set of temporary objects that may be individually saved and retrieved.A Pool is safe for use by multiple goroutines simultaneously.

sync.Pool allows us to reuse memory without allocate.

Also if you are have http server which wait post requests with json body and it must decode to the structure you can use sync.Pool to save memory and reduce server response time.

sync.Pool usage

sync.Pool construction is simple:

var bufferPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}

Now you have pool which will be create and new buffers. You can get you first buffer here:

buffer := bufferPool.Get().(*bytes.Buffer)

Method get will return already existing *bytes.Buffer in the pool and if it’s not will call method New which init new *bytes.Buffer

But after buffer usage you must reset and put it to pool back:

buffer.Reset()
bufferPool.Put(buffer)

Benchmarking

Encoding json to the bytes.Buffer

// That code tried to json encode structureBenchmarkReadStreamWithPool-8        5000000        384 ns/op        0 B/op        0 allocs/op
BenchmarkReadStreamWithoutPool-8 3000000 554 ns/op 160 B/op 2 allocs/op

We have 44% performance boost and save very-very much memory (160B/ops vs 0B/ops)

Writing bytes to bufio.Writer

BenchmarkWriteBufioWithPool-8       10000000        123 ns/op      128 B/op        2 allocs/op
BenchmarkWriteBufioWithoutPool-8 2000000 651 ns/op 4288 B/op 4 allocs/op

We have x5 performance boost and x32 reduced memory usage

Decoding json to struct

BenchmarkJsonDecodeWithPool-8        1000000       1729 ns/op     1128 B/op        8 allocs/op
BenchmarkJsonDecodeWithoutPool-8 1000000 1751 ns/op 1160 B/op 9 allocs/op

We have 1% performance boost because json decode is too hard operation and we cannot see normal boost by the reusing structures.

Gzip bytes

BenchmarkWriteGzipWithPool-8          500000       2339 ns/op      162 B/op        2 allocs/op
BenchmarkWriteGzipWithoutPool-8 10000 105288 ns/op 807088 B/op 16 allocs/op

Stop, what? x45 performance boost and x4982 reduced memory usage

Conclusion

Always use sync.Pool when you can! It really saves memory and increase performance of you application.

Github repository with benchmarks here.

📝 Read this story later in Journal.

👩‍💻 Wake up every Sunday morning to the week’s most noteworthy stories in Tech waiting in your inbox. Read the Noteworthy in Tech newsletter.

--

--

Mikhail Panfilov
Mikhail Panfilov

Responses (1)