How to Use sync.Once in Go for One-Time Execution
In Go,
sync.Once ensures a function runs only once, even if called from multiple goroutines. Use its Do method with the function you want to execute exactly one time.Syntax
The sync.Once type has a method Do(f func()) that runs the function f only once. Even if multiple goroutines call Do, f executes just one time.
var once sync.Once: declares aOncevariable.once.Do(func()): runs the function once.
go
var once sync.Once once.Do(func() { // code to run once })
Example
This example shows how sync.Once runs initialization code only once, even when called from multiple goroutines.
go
package main import ( "fmt" "sync" ) var once sync.Once func initialize() { fmt.Println("Initialization done") } func worker(id int, wg *sync.WaitGroup) { defer wg.Done() once.Do(initialize) fmt.Printf("Worker %d done\n", id) } func main() { var wg sync.WaitGroup for i := 1; i <= 3; i++ { wg.Add(1) go worker(i, &wg) } wg.Wait() }
Output
Initialization done
Worker 1 done
Worker 2 done
Worker 3 done
Common Pitfalls
One common mistake is calling Do with a function that has side effects or depends on external state that changes, expecting it to run multiple times. sync.Once runs the function only once, so subsequent calls do nothing.
Another pitfall is trying to reuse the same sync.Once variable to run different functions multiple times; it only allows one function execution ever.
go
package main import ( "fmt" "sync" ) func main() { var once sync.Once // Wrong: trying to run two different functions with the same Once once.Do(func() { fmt.Println("First run") }) once.Do(func() { fmt.Println("Second run") }) // This will NOT run // Correct: use separate Once variables for different one-time actions var once2 sync.Once once2.Do(func() { fmt.Println("Second run") }) }
Output
First run
Second run
Quick Reference
- sync.Once: type to ensure one-time execution.
- Do(func()): runs the function once, ignores later calls.
- Safe for concurrent use by multiple goroutines.
- Use separate
sync.Oncevariables for different one-time actions.
Key Takeaways
Use sync.Once.Do to run a function exactly once, even with many goroutines.
sync.Once is safe for concurrent use without extra locking.
Do not expect the function to run more than once per sync.Once variable.
Use separate sync.Once variables for different one-time initializations.
sync.Once helps avoid race conditions in one-time setup code.