Table of Contents

Go Design Decisions

Decision patterns, reasoning and tradeoffs for idiomatic Go software design

Concurrency: sync.Map vs. map with sync.Mutex

Both `sync.Map` and `map` with `sync.Mutex` are concurrency-safe options in Go. The choice depends on runtime access patterns and operational requirements.

Example: Global Map as Registry

// Using sync.Map
import "sync"
 
var registry sync.Map
 
func register(key string, value any) {
  registry.Store(key, value)
}
 
func get(key string) (any, bool) {
  return registry.Load(key)
}
// Using map + sync.Mutex
import "sync"
 
var (
  mu       sync.Mutex
  registry = make(map[string]any)
)
 
func register(key string, value any) {
  mu.Lock()
  defer mu.Unlock()
  registry[key] = value
}
 
func get(key string) (any, bool) {
  mu.Lock()
  defer mu.Unlock()
  val, ok := registry[key]
  return val, ok
}

When to Use What

Use sync.Map when:

  1. You expect high-frequency concurrent access (many readers/writers)
  2. The map is accessed from many goroutines over a long time
  3. The key set is dynamic and large
  4. You want to minimize explicit locking logic

Use map with sync.Mutex when:

  1. You expect low to moderate concurrency
  2. The map has a small, mostly static set of keys
  3. You want full control over locking and error handling
  4. You prefer simple and readable code for initialization-time usage

Both approaches are valid and safe. Choose based on expected load, not based on subjective stylistic preferences.