Skip to content

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.

go
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

go
type Once struct {
    done atomic.Uint32
    m    Mutex
}

Its internal structure is very simple:

  1. done, an atomic value, used to indicate whether it has been executed
  2. m, 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

go
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:

  1. Directly load the atomic value, if already executed, return immediately
  2. If not executed, try to acquire the lock, here multiple goroutines may be competing for the mutex
  3. After the winner successfully acquires the lock, it still needs to check the done value again, because after you acquire the lock, someone else may have already completed the lock-acquire-execute-unlock sequence, and you were just awakened.
  4. Execute the target function
  5. Update the done value
  6. 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.

Golang by www.golangdev.cn edit