Sobes.tech
Middle+

Какви са атомарните операции, какви видове съществуват и кога и как е по-добре да ги използваме?

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
}

Важно е да се помни, че атомарните операции работят с примитивни типове данни (цяли числа, указатели). За синхронизация на достъпа до по-сложни структури или изпълнение на блокиращи операции все още са необходими мьютекси или други механизми за синхронизация. Прекомерната или неправилна употреба на атомарните операции може да доведе до трудноуловими грешки или намалена производителност.