programming

Getting to know the Sync Pool on Golang

Introduction to sync.Pool

We often hear sync.Pool when implementing a design pattern called Object Pool Pattern. A Pool is a temporary set of objects that can be stored and retrieved individually. A Pool is safe to be used by multiple goroutines simultaneously.

sync.Pool allows us to reuse memory without allocating. Also if we have an http server waiting for a POST request with a json body and has to decode into a structure, then you can use sync.Pool to save memory and reduce the response time of the server.

Why should we use sync.Pool?

The purpose of Pool is to temporarily store allocated but unused items for reuse so as to reduce collection from the garbage collector.

The proper use of Pool is indeed to manage a group of temporary items that are shared and can be reused by clients independently.

The most important thing to note is that Pool has its own performance cost. It is much slower to use sync.Pool than simple initialization.

Usage

sync.Pool provides several built-in methods including:

  • Get() is used to retrieve data from a Pool, then remove it from the Pool and return the retrieved data.
  • Put(x any) is used to store data into the Pool that we have initialized.

Implementation and sample of sync.Pool

Now we will see how simple it is to implement sync.Pool. First, we will use sync.Pool where we will make a function that generates an object and returns data when it is called.

package main

import (
    "fmt"
    "sync"
)

type Person struct {
    Name string
}

var pool = sync.Pool{
    New: func() any {
        fmt.Println("Creating a new person...")
        return &Person{}
    },
}

func main() {
    person := pool.Get().(*Person)
    fmt.Println("Get the object from sync.Pool for the first time:", person)

    fmt.Println("Put the object back in the pool")
    pool.Put(person)

    person.Name = "Gopher"
    fmt.Println("Set object property name:", person.Name)

    fmt.Println("Get object from pool again (it's updated):", pool.Get().(*Person))
    fmt.Println("There is no object in the pool now (new one will be created):", pool.Get().(*Person))
}

And if we run it, we will see the output as below:

$ go run main.go
Creating a new person...
Get the object from sync.Pool for the first time: &{}
Put the object back in the pool
Set object property name: Gopher
Get the object from the pool again (it's updated): &{Gopher}
Creating a new person...
There is no object in the pool now (a new one will be created): &{}

Conclusion

Notice how when we remove the data from the Pool it will disappear in the Pool so this is suitable for storing some temporary objects shared between goroutines.

comments powered by Disqus