WaitGroup: дождаться всех
Клиент присылал папку целиком, и отчёт о загрузке уходил раньше, чем обрабатывался последний файл. Миша ввёл счётчик: каждая задача регистрировалась при старте и отмечала завершение, а отчёт уходил, только когда счётчик обнулялся.
WaitGroup считает незавершённые горутины: Add до старта, Done при завершении, Wait — дождаться, пока счётчик станет нулём.
Базовая схема
var wg sync.WaitGroup
for _, f := range files {
wg.Add(1) // регистрируем горутину ДО её запуска
go func(f File) {
defer wg.Done() // гарантированно выполнится при выходе
process(f)
}(f)
}
wg.Wait() // блокируемся, пока все не завершатся
Add(1) увеличивает счётчик, Done уменьшает, Wait блокируется до нуля. Add обязано быть до go — иначе возможна гонка: Wait может проскочить, пока горутины ещё не зарегистрировались. defer wg.Done гарантирует вызов на любом пути, включая панику.
WaitGroup переиспользуется
После возврата Wait счётчик равен нулю, и ту же WaitGroup можно использовать снова — для следующего пакета. Но документация требует: новые Add для следующей партии — после возврата предыдущего Wait. Дождались всех, только потом начинаем новых.
Чего WaitGroup не умеет
Ошибок она не возвращает. Если одна из десяти задач упала, Wait ничего об этом не скажет — собирать ошибки придётся самим: канал, мьютекс, атомарный флаг. Для задачи «запустить N задач и собрать первую ошибку» есть golang.org/x/sync/errgroup (урок).
Вы узнаете:
- как happens-before работает через Done и Wait
- когда использовать WaitGroup, а когда done-канал
Проверьте себя
Горутины пишут results[i] = i * i, затем main делает wg.Wait() и читает results. Что гарантированно видно?
Когда можно делать новые Add после переиспользования WaitGroup?
Что WaitGroup НЕ умеет?
правильных ответов
WaitGroup — счётчик: Add до старта, Done через defer, Wait после. Не собирает ошибки, не лимитирует, не отменяет.
10 000 ₽ · 60 минут · онлайн