👨💻 Ошибки с sync.WaitGroup
sync.WaitGroup — один из самых простых синхронизационных примитивов в Go. Его задача предельно ясна: дождаться, пока несколько горутин закончат работу.
sync.WaitGroup состоит из трех операций: Add() говорит «я жду еще одну горутину», Done() говорит «эта горутина закончила», Wait() блокирует до того, как счетчик вернется к нулю.
Но вот где начинаются проблемы:
Вызов Add() после запуска горутины:
go func() {
wg.Add(1) // слишком поздно!
doWork()
wg.Done()
}()
wg.Wait()
Главная горутина может выйти из Wait() прежде, чем дочерняя вызовет Add(). Вот вам race condition.
Забыли Done():
go func() {
doWork()
// забыли wg.Done()
}()
wg.Wait() // будет висеть вечноWait() никогда не вернется, потому что счетчик никогда не уменьшится.
Wait() в неправильном месте:
for _, item := range items {
go func(i Item) {
wg.Add(1)
defer wg.Done()
doWork(i)
}(item)
wg.Wait() // внутри цикла! это синхронное выполнение
}Wait() внутри цикла превращает параллельное выполнение в последовательное. Вы ждете каждой горутины перед запуском следующей.
Запомните: WaitGroup — инструмент для синхронизации конца работы, а не управления её началом.
🐸 Библиотека Go-разработчика
#GoDeep