How to share memory between goroutines? When is it better to use Atomic, and when Mutex/RWMutex/SyncMap?
sobes.tech AI
Answer from AI
In Go, different mechanisms are used for sharing memory between goroutines depending on the task:
-
Atomic (package sync/atomic) is suitable for simple operations with primitive types (int, uint64, pointers), when you need to quickly and lock-free modify or read a value. Good for counters, flags, where operations are atomic and do not require complex logic.
-
Mutex / RWMutex (sync.Mutex, sync.RWMutex) are used when you need to protect access to more complex data structures or when operations are not just simple atomic changes. Mutex blocks access, RWMutex allows multiple readers simultaneously, but only one writer.
-
Sync.Map — a specialized thread-safe map optimized for cases with many reads and relatively rare writes. Convenient when you need to store key-value pairs with concurrent access without manual lock management.
Choice:
- If high performance and simple operations are needed — atomic.
- If data is complex or operations are complex — mutex/RWMutex.
- If a thread-safe map with a convenient API is needed — sync.Map.
Example of using atomic for a counter:
var counter int64
func increment() {
atomic.AddInt64(&counter, 1)
}
func get() int64 {
return atomic.LoadInt64(&counter)
}
Example with mutex to protect a slice:
var mu sync.Mutex
var data []int
func add(val int) {
mu.Lock()
defer mu.Unlock()
data = append(data, val)
}
func getAll() []int {
mu.Lock()
defer mu.Unlock()
return append([]int(nil), data...)
}