sync.WaitGroupsync.WaitGroup содержит три поля: noCopy, state atomic.Uint64 и sema uint32.noCopy — маркер для go vet, запрещает копирование структуры после первого использования. В рантайме не занимает места.state — ключевое поле. В одном 64-битном слове упакованы два счётчика: старшие 32 бита — counter, количество незавершённых горутин, младшие 32 бита — waiter, количество горутин, заблокированных в Wait. Упаковка в одно слово нужна, чтобы атомарно обновлять оба значения за одну операцию и исключить гонку между Add и Wait.sema — системный семафор рантайма. Когда горутина вызывает Wait и counter > 0, она атомарно инкрементирует waiter и паркуется через runtime_Semacquire. Когда Add обнуляет counter, он делает runtime_Semrelease столько раз, сколько горутин ждёт.Done() — это просто Add(-1). Если после Add(delta) значение counter уходит в минус, рантайм паникует с "sync: negative WaitGroup counter".🐸 Библиотека Go для собеса