Using GO Sync.Once
sync.Once is used to ensure that a function executes only once, regardless of how many goroutines attempt to execute it. It has one method Do(f func()) that takes the function to be executed.
Basic usage example:
package main
import (
"fmt"
"sync"
)
func main() {
var once sync.Once
done := make(chan bool)
// Simulate multiple goroutines calling
for i := 0; i < 10; i++ {
go func(x int) {
// The function passed to once.Do() will only execute once
once.Do(func() {
fmt.Printf("Execute only once: %d\n", x)
})
// This line will be executed by every goroutine
fmt.Printf("goroutine %d completed\n", x)
done <- true
}(i)
}
// Wait for all goroutines to complete
for i := 0; i < 10; i++ {
<-done
}
}
Common use cases:
-
Singleton pattern:
type Singleton struct{} var ( instance *Singleton once sync.Once ) func GetInstance() *Singleton { once.Do(func() { instance = &Singleton{} }) return instance }
-
One-time initialization:
type Config struct { settings map[string]string once sync.Once } func (c *Config) Load() { c.once.Do(func() { // Configuration loading code c.settings = make(map[string]string) c.settings["key"] = "value" }) }
-
Delayed resource closing:
type Connection struct { once sync.Once quit chan struct{} } func (c *Connection) Close() { c.once.Do(func() { close(c.quit) }) }
-
Error handling:
type ErrorHandler struct { once sync.Once err error } func (e *ErrorHandler) HandleError(err error) { e.once.Do(func() { e.err = err // Only handle the first error fmt.Println("Handling error:", err) }) }
Characteristics of sync.Once:
- Thread-safe: Can be safely used across multiple goroutines
- Execute only once: No matter how many times it’s called, the passed function will only execute once
- All goroutines will wait for the first execution to complete
- No retry on failure: If the function execution fails, subsequent calls will not re-execute
- Cannot be reset: Once executed, it cannot be restarted
It’s important to note that sync.Once’s Do method only guarantees the function executes once, but doesn’t guarantee which goroutine executes it. If multiple goroutines call simultaneously, only one will execute the function while the others wait for completion.