Что такое атомарные операции, какие их виды существуют, и когда и как их лучше использовать?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Атомарные операции — это операции над памятью, выполнение которых гарантированно завершается либо полностью, либо не начинается вовсе, и они не могут быть прерваны другими конкурирующими операциями. Они являются неделимыми и потокобезопасными на аппаратном уровне.
В Go пакет sync/atomic предоставляет набор функций для выполнения атомарных операций:
| Функция | Описание |
|---|---|
AddInt32 |
Атомарно добавляет значение к int32. |
AddInt64 |
Атомарно добавляет значение к int64. |
AddUint32 |
Атомарно добавляет значение к uint32. |
AddUint64 |
Атомарно добавляет значение к uint64. |
AddUintptr |
Атомарно добавляет значение к uintptr. |
CompareAndSwapInt32 |
Атомарно сравнивает и обменивает (CAS) int32. |
CompareAndSwapInt64 |
Атомарно сравнивает и обменивает (CAS) int64. |
CompareAndSwapUint32 |
Атомарно сравнивает и обменивает (CAS) uint32. |
CompareAndSwapUint64 |
Атомарно сравнивает и обменивает (CAS) uint64. |
CompareAndSwapUintptr |
Атомарно сравнивает и обменивает (CAS) uintptr. |
CompareAndSwapPointer |
Атомарно сравнивает и обменивает (CAS) unsafe.Pointer. |
LoadInt32 |
Атомарно загружает значение int32. |
LoadInt64 |
Атомарно загружает значение int64. |
LoadUint32 |
Атомарно загружает значение uint32. |
LoadUint64 |
Атомарно загружает значение uint64. |
LoadUintptr |
Атомарно загружает значение uintptr. |
LoadPointer |
Атомарно загружает значение unsafe.Pointer. |
StoreInt32 |
Атомарно сохраняет значение int32. |
StoreInt64 |
Атомарно сохраняет значение int64. |
StoreUint32 |
Атомарно сохраняет значение uint32. |
StoreUint64 |
Атомарно сохраняет значение uint64. |
StoreUintptr |
Атомарно сохраняет значение uintptr. |
StorePointer |
Атомарно сохраняет значение unsafe.Pointer. |
SwapInt32 |
Атомарно обменивает значения int32. |
SwapInt64 |
Атомарно обменивает значения int64. |
SwapUint32 |
Атомарно обменивает значения uint32. |
SwapUint64 |
Атомарно обменивает значения uint64. |
SwapUintptr |
Атомарно обменивает значения uintptr. |
SwapPointer |
Атомарно обменивает значения unsafe.Pointer. |
Использовать атомарные операции лучше всего в случаях, когда требуется простая, низкоуровневая синхронизация доступа к общим переменным, чаще всего счетчикам или флагам, без использования мьютексов. Они обеспечивают минимальные накладные расходы и лучшую производительность по сравнению с мьютексами в таких сценариях.
Пример использования атомарного счетчика:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var counter int64
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
// Атомарно увеличиваем счетчик
atomic.AddInt64(&counter, 1)
wg.Done()
}()
}
wg.Wait()
// Атомарно загружаем значение счетчика
fmt.Println("Final Counter:", atomic.LoadInt64(&counter))
}
Пример использования CompareAndSwap:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var value int32 = 10
// Попытка обменять значение, если текущее равно 10, на 20
swapped := atomic.CompareAndSwapInt32(&value, 10, 20)
fmt.Println("Swapped:", swapped) // Swapped: true
fmt.Println("Value:", value) // Value: 20
// Попытка обменять значение, если текущее равно 10, на 30
swapped = atomic.CompareAndSwapInt32(&value, 10, 30)
fmt.Println("Swapped:", swapped) // Swapped: false
fmt.Println("Value:", value) // Value: 20
}
Важно помнить, что атомарные операции работают с примитивными типами данных (целые числа, указатели). Для синхронизации доступа к более сложным структурам данных или выполнения блокирующих операций по-прежнему требуются мьютексы или другие механизмы синхронизации. Чрезмерное или неправильное использование атомарных операций может привести к трудноотлавливаемым ошибкам или снижению производительности.