Как шарить память между горутинами? В каких случаях лучше использовать Atomic, а в каких Mutex/RWMutex/SyncMap?
Ответ от нейросети
sobes.tech AI
В Go для шаринга памяти между горутинами используют разные механизмы в зависимости от задачи:
-
Atomic (пакет sync/atomic) подходит для простых операций с примитивными типами (int, uint64, указатели), когда нужно быстро и без блокировок изменять или читать значение. Хорош для счётчиков, флагов, где операции атомарны и не требуют сложной логики.
-
Mutex / RWMutex (sync.Mutex, sync.RWMutex) используются, когда нужно защитить доступ к более сложным структурам данных или когда операции не сводятся к простому атомарному изменению. Mutex блокирует доступ, RWMutex позволяет нескольким читателям одновременно, но только одного писателя.
-
Sync.Map — специализированная потокобезопасная карта, оптимизированная для случаев с большим количеством чтений и сравнительно редкими записями. Удобна, когда нужно хранить ключ-значение с конкурентным доступом без ручного управления блокировками.
Выбор:
- Если нужна высокая производительность и операции простые — atomic.
- Если данные сложные или операции комплексные — mutex/RWMutex.
- Если нужно потокобезопасное отображение с удобным API — sync.Map.
Пример использования atomic для счётчика:
var counter int64
func increment() {
atomic.AddInt64(&counter, 1)
}
func get() int64 {
return atomic.LoadInt64(&counter)
}
Пример с mutex для защиты среза:
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...)
}