# sync.Once, sync/atomic and sync.Map — Go Concurrency Patterns

Source: https://www.geekswithgeeks.com/en/go-concurrency/gc-once-atomic

> Smaller tools for specific jobs.

## Choosing the right primitive

`sync.Once` runs a function exactly once, even when many goroutines call `once.Do(f)` simultaneously; the others wait until it has finished. It is ideal for lazy initialisation. Go 1.21 added the helpers `sync.OnceFunc`, `sync.OnceValue` and `sync.OnceValues`. The `sync/atomic` package offers lock-free operations; since Go 1.19 the typed values `atomic.Int64`, `atomic.Bool`, `atomic.Pointer[T]` and friends are the easiest way to use them. Atomics suit single counters and flags, but they do not make multi-field updates consistent; use a mutex for that. `sync.Map` is a concurrent map optimised for two cases described in its docs: keys written once and read many times, or goroutines working on disjoint key sets. For most other workloads, a plain map with a Mutex is simpler and type-safe.

## Lazy config with OnceValue and an atomic counter

Two small primitives used together.

```go
package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

type Config struct{ Region string }

// loadConfig runs at most once, on first call, even under concurrency.
var loadConfig = sync.OnceValue(func() *Config {
	fmt.Println("loading config")
	return &Config{Region: "eu-west"}
})

var requests atomic.Int64

func handle() {
	requests.Add(1)
	_ = loadConfig().Region
}

func main() {
	var wg sync.WaitGroup
	for range 100 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			handle()
		}()
	}
	wg.Wait()
	fmt.Println("requests:", requests.Load()) // 100; "loading config" printed once
}
```

## Do not mix atomic and plain access

If a variable is accessed atomically anywhere, every access must be atomic. A single plain read of a field that others update with atomic operations is a data race.

**Quiz:** Which use case does the sync.Map documentation describe as a good fit?

- [ ] Any map shared between goroutines
- [x] Keys that are written once and read many times
- [ ] Maps whose values must be updated together in transactions
- [ ] Small maps accessed by a single goroutine

*Answer:* Keys that are written once and read many times. For general use a map plus a Mutex is usually simpler and type-safe.
