Go sync.Once: A Powerful Tool for Controlled Execution 🎯

beginner
6 min

Go sync.Once: A Powerful Tool for Controlled Execution 🎯

Welcome to our deep dive into the fascinating world of synchronization in Go! Today, we'll explore the sync.Once type, a powerful tool that ensures a piece of code is executed at most once in a Go program. Let's get started!

What is sync.Once? 📝

The sync.Once type is a Go synchronization primitive that guarantees the execution of a block of code exactly once during the lifetime of the program. It's particularly useful when you want to perform an expensive initialization task or set up a resource that should only be initialized once.

Creating a sync.Once object 💡

To create a sync.Once object, simply call the sync.Once function.

go
package main import ( "fmt" "sync" ) var initOnce sync.Once

In the code above, we've declared a sync.Once variable named initOnce.

Using sync.Once to initialize a resource 💡

Now let's see how to use sync.Once to initialize a resource safely. In this example, we'll create a database connection that should only be established once.

go
package main import ( "database/sql" "fmt" "log" "sync" _ "github.com/go-sql-driver/mysql" ) var db *sql.DB var initDB sync.Once func initDatabase() *sql.DB { var err error db, err = sql.Open("mysql", "user:pass@tcp(localhost:3306)/database_name") if err != nil { log.Fatal(err) } return db } func main() { initDB.Do(initDatabase) fmt.Println("Database connection established.") // Use the database connection here }

In the code above, we've defined a function initDatabase() that sets up a MySQL database connection. We've also created a sync.Once variable initDB and used the Do() method to execute the initDatabase() function exactly once.

Do() method 💡

The Do() method takes a closure (a function with access to the surrounding variables) as an argument and ensures that the closure is only executed once during the lifetime of the sync.Once object.

Advanced usage 💡

You can also use the sync.Once object multiple times within a single program. In such cases, the Do() method will only execute the closure if it hasn't been executed before.

go
package main import ( "fmt" "sync" ) var initOnce sync.Once func init() { initOnce.Do(func() { fmt.Println("Initialization complete.") }) } func main() { initOnce.Do(func() { fmt.Println("Initialization attempted again.") }) fmt.Println("Main function execution.") }

In the code above, we've defined a function init() that initializes the program. We've also declared a global sync.Once variable initOnce. Inside the main() function, we attempt to execute the closure of initOnce again, but since it has already been executed, nothing happens.

Quiz 🎯

Quick Quiz
Question 1 of 1

What guarantees the execution of a block of code exactly once during the lifetime of a Go program using `sync.Once`?

That's all for today! We've covered the basics of the sync.Once type in Go and seen how it can be used to ensure controlled execution of code. In the next lesson, we'll dive deeper into Go synchronization primitives and explore the sync.Mutex type. Stay tuned! 🚀