Ответ
Нет, атомарные операции не являются блокирующими. Это низкоуровневые примитивы синхронизации, которые выполняются как единая, неделимая инструкция на уровне процессора. Они lock-free, то есть не используют мьютексы.
Ключевое отличие от мьютексов (sync.Mutex
):
- Мьютекс: Если горутина пытается захватить заблокированный мьютекс, планировщик Go приостанавливает её (блокирует) и переключается на другую горутину. Это может привести к переключению контекста.
- Атомарная операция: Горутина не блокируется планировщиком. Операция выполняется очень быстро с использованием специальных инструкций процессора (например,
Compare-And-Swap
). Это позволяет избежать накладных расходов на переключение контекста.
Пример (потокобезопасный счетчик):
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var counter int64
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
// Неблокирующая, безопасная операция инкремента
atomic.AddInt64(&counter, 1)
}()
}
wg.Wait()
fmt.Println("Final Counter:", counter) // 1000
}
Когда что использовать:
sync/atomic
: Идеально подходит для простых операций над примитивными типами: счетчики, флаги, безопасное чтение/запись указателей. Обеспечивает максимальную производительность.sync.Mutex
: Используется для защиты сложных структур данных или для выполнения последовательности из нескольких операций как единого целого (транзакции).