Назад к вопросам
Middle+
158
questionbank

Что такое атомарные операции, какие их виды существуют, и когда и как их лучше использовать?

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
}

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