sync.Once
Use `sync.Once` or `OnceValue` for one-time shared initialization; do not open-code racy lazy init.
Canonical guidance
- use
sync.Oncefor shared one-time initialization - prefer
OnceValueorOnceValueswhen the result should be returned cleanly - keep the initialization path simple and idempotent enough for one execution
Use when
- lazy singletons
- cached expensive setup
- shared initialization across many goroutines
Avoid
- hand-rolled boolean-plus-mutex init guards
- assuming
sync.Oncesupports reset - using once when eager package init would be simpler
Preferred pattern
var loadConfig = sync.OnceValue(func() Config {
return readConfig()
})
Anti-pattern
- checking
if x == nilwithout synchronization and then initializing from several goroutines
Explanation: This anti-pattern is tempting because it looks cheap, but it is exactly the kind of publication bug sync.Once exists to avoid.
Why
- once-based initialization is clearer and safer than open-coded lazy init races
Related pages
Sources
- sync package - Go Team
- The Go Memory Model - Go Team