Материал проходит вычитку — возможны неточности.
Урок 85 из 118

Ошибки WaitGroup

Первый запуск со счётчиком дал странный симптом: программа завершалась, не дождавшись задач пакета. Миша нашёл баг — счётчик ожидания увеличивали уже после старта задачи, внутри неё самой. Он перенёс регистрацию до запуска, и отчёт снова дожидался всех.

Главная мысль

у WaitGroup три классические ошибки: Add внутри горутины (гонка), копирование структуры (вешает Wait) и отрицательный счётчик (паника).

Add внутри горутины

var wg sync.WaitGroup

for _, f := range files {
    go func(f File) {
        wg.Add(1) // баг: Add после запуска
        defer wg.Done()
        process(f)
    }(f)
}

wg.Wait()

Wait может вернуться до того, как горутины сделают Add: счётчик ещё ноль, ждать нечего. Add обязан стоять до go — это условие, а не стиль.

Копирование

var wg sync.WaitGroup
wg.Add(1)

wg2 := wg // копия внутреннего состояния
go func() { wg2.Done() }()

wg.Wait() // deadlock: оригинальная wg никогда не узнает о Done

WaitGroup копировать нельзя. Done по копии уменьшает счётчик копии, а Wait ждёт оригинал — навсегда. Правило: передавай WaitGroup только по указателю, идиоматично — в замыкании горутины использовать ту же переменную.

Отрицательный счётчик

var wg sync.WaitGroup
wg.Done() // panic: negative WaitGroup counter

Done без Add уводит счётчик в минус — паника. Обычно это симптом парного бага: либо Add потерялся, либо Done вызван дважды (например, Done и в defer, и в теле).

В следующем уроке

Вы узнаете:

  • как race detector ловит Add в горутине
  • как go vet ловит копии блокировок
Задание · вопросы

Проверьте себя

Вопрос 1 из 3

var wg sync.WaitGroup; wg.Done() без Add. Что произойдёт?

Вопрос 2 из 3

Почему нельзя копировать WaitGroup?

Вопрос 3 из 3

Как защититься от двойного Done?

Итоги

Add — до старта и вне горутины; копий не делать; Done — ровно по одному на Add. Три правила, три симптома: гонка, дедлок, паника.

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки