Ответ
Пакет sync
предоставляет основные примитивы синхронизации, необходимые для написания безопасного и корректного конкурентного кода в Go.
Основные примитивы:
Mutex
иRWMutex
: Мьютексы для эксклюзивной блокировки.sync.Mutex
предоставляет полную блокировку, аsync.RWMutex
— блокировку для чтения/записи, позволяя множеству горутин читать данные одновременно, но только одной — изменять их.WaitGroup
: Механизм для ожидания завершения работы группы горутин. Основные методы:Add(n)
для увеличения счетчика,Done()
для его уменьшения иWait()
для блокировки до тех пор, пока счетчик не станет равен нулю.Once
: Гарантирует, что определенный участок кода (функция) будет выполнен только один раз за все время работы программы, независимо от количества одновременных вызовов.Pool
: Пул для переиспользования объектов, что позволяет снизить нагрузку на сборщик мусора (GC). Полезен для временных объектов, которые часто создаются и уничтожаются.Map
: Потокобезопасная реализацияmap
. Оптимизирована для сценариев, где ключ записывается один раз, а затем многократно читается множеством горутин. Для сценариев с частыми записями и удалениями более эффективным может быть использование обычнойmap
сsync.Mutex
.Cond
: Условная переменная, которая позволяет горутинам ожидать наступления определенного события или изменения условия. Работает в связке сMutex
.
Примеры:
Mutex
для защиты счетчика:
var mu sync.Mutex
var counter int
func increment() {
mu.Lock()
defer mu.Unlock()
counter++
}
WaitGroup
для ожидания завершения воркеров:
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1) // Увеличиваем счетчик перед запуском горутины
go func(workerID int) {
defer wg.Done() // Уменьшаем счетчик при завершении
fmt.Printf("Воркер %d завершил работуn", workerID)
}(i)
}
wg.Wait() // Ожидаем, пока счетчик не станет 0
fmt.Println("Все воркеры завершили работу")