once
sync.Once is a synchronization tool in Go's standard library, used to ensure that a function is executed only once in a concurrent environment. It's commonly used in scenarios such as lazy initialization, global resource initialization, etc., ensuring that a specific operation is executed only once, even when multiple goroutines are executing concurrently.
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
var once sync.Once
for i := range 10 {
wg.Add(1)
go func() {
defer wg.Done()
once.Do(func() {
fmt.Println(i)
})
}()
}
wg.Wait()
}In the above code, there are a total of 10 goroutines, but regardless, only one goroutine will execute fmt.Println(i) in once.Do(). Which goroutine prints depends on which goroutine reaches once.Do() first.
Structure
type Once struct {
done atomic.Uint32
m Mutex
}Its internal structure is very simple:
done, an atomic value, used to indicate whether it has been executedm, mutex lock, used to block other goroutines that want to execute
Its principle is to lock before execution, then update done, and unlock after execution is complete.
Do
func (o *Once) Do(f func()) {
if o.done.Load() == 0 {
o.doSlow(f)
}
}
func (o *Once) doSlow(f func()) {
o.m.Lock()
defer o.m.Unlock()
if o.done.Load() == 0 {
defer o.done.Store(1)
f()
}
}The code is overall very simple, with the following flow:
- Directly load the atomic value, if already executed, return immediately
- If not executed, try to acquire the lock, here multiple goroutines may be competing for the mutex
- After the winner successfully acquires the lock, it still needs to check the
donevalue again, because after you acquire the lock, someone else may have already completed the lock-acquire-execute-unlock sequence, and you were just awakened. - Execute the target function
- Update the
donevalue - Release the lock
Summary
sync.Once is a very concise and efficient synchronization tool. It ensures that a certain operation is executed only once in a concurrent environment, thereby avoiding duplicate work or resource waste.
