Проверяет понимание корректного использования WaitGroup в Go, особенно вызова Add внутри горутины.
В Go пакет sync предоставляет тип WaitGroup для ожидания завершения группы горутин. Основные методы: Add увеличивает счетчик, Done уменьшает его, а Wait блокирует выполнение до тех пор, пока счетчик не станет нулевым. Вопрос о том, можно ли вызывать Add внутри горутины, часто возникает у новичков, но важно понимать, как это влияет на корректность и безопасность.
Если вызвать Add внутри горутины, а Done в конце той же горутины, программа может работать корректно в простых случаях. Например:
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
go func() {
wg.Add(1)
defer wg.Done()
// выполнение работы
}()
}
wg.Wait()Здесь Add вызывается внутри каждой горутины, и Wait ожидает завершения всех. Однако есть риск: если Wait вызывается до того, как горутины успеют выполнить Add, счетчик может быть нулевым, и Wait вернется немедленно, не дождавшись горутин. Это приводит к гонке данных и непредсказуемому поведению.
Рекомендуется вызывать Add до запуска горутины, чтобы счетчик был установлен до вызова Wait. Это гарантирует, что Wait будет ожидать все горутины. Пример:
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
// выполнение работы
}()
}
wg.Wait()Такой подход безопасен и является стандартной практикой в Go.
Хотя вызов Add внутри горутины может работать в простых случаях, это создает риск гонок данных и непредсказуемого поведения. Всегда вызывайте Add до запуска горутины, чтобы обеспечить корректное ожидание завершения всех горутин.