Проверяет знание механизмов синхронизации в Go для безопасной работы с многопоточностью.
Go предоставляет несколько механизмов для синхронизации горутин, каждый из которых решает свою задачу. Основной принцип — «не общайтесь через разделяемую память, а разделяйте память через общение», что подчеркивает важность каналов.
Каналы — это типизированные трубы, через которые горутины передают данные. Они обеспечивают синхронизацию: отправка и получение блокируют горутину до готовности другой стороны. Каналы бывают буферизированными и небуферизированными. Пример:
ch := make(chan int)
go func() { ch <- 42 }()
value := <-ch // получаем 42Мьютекс защищает критическую секцию, позволяя только одной горутине одновременно выполнять код. Используется, когда нужно защитить общие данные от гонок. Пример:
var mu sync.Mutex
var counter int
mu.Lock()
counter++
mu.Unlock()WaitGroup ожидает завершения набора горутин. Метод Add увеличивает счетчик, Done уменьшает, Wait блокирует до нуля. Пример:
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() { defer wg.Done(); work() }()
}
wg.Wait()Пакет sync/atomic предоставляет функции для атомарного чтения и записи простых типов (int32, int64, указатели). Это быстрее мьютексов для простых операций. Пример:
var counter int32
atomic.AddInt32(&counter, 1)Выбор механизма зависит от задачи: каналы — для передачи данных и координации, мьютексы — для защиты сложных структур, WaitGroup — для ожидания группы горутин, атомарные операции — для простых счетчиков. Правильное использование этих инструментов обеспечивает безопасность и производительность многопоточного кода.