Какви са атомарните операции, какви видове съществуват и кога и как е по-добре да ги използваме?
sobes.tech AI
Отговор от 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
}
Важно е да се помни, че атомарните операции работят с примитивни типове данни (цяли числа, указатели). За синхронизация на достъпа до по-сложни структури или изпълнение на блокиращи операции все още са необходими мьютекси или други механизми за синхронизация. Прекомерната или неправилна употреба на атомарните операции може да доведе до трудноуловими грешки или намалена производителност.