Что делает метод `Wait()` у `sync.WaitGroup`?

Ответ

Метод Wait() типа sync.WaitGroup блокирует выполнение текущей горутины до тех пор, пока внутренний счетчик WaitGroup не станет равен нулю.

Это основной механизм для синхронизации и ожидания завершения группы горутин. Главная горутина (или любая другая) может вызвать wg.Wait(), чтобы дождаться, пока все "рабочие" горутины выполнят свою задачу.

Жизненный цикл WaitGroup:

  1. Add(n): Перед запуском горутин счетчик увеличивается на n (количество горутин, которые нужно ожидать).
  2. Запуск горутин: В каждой горутине с помощью defer вызывается Done().
  3. Done(): Уменьшает внутренний счетчик на единицу.
  4. Wait(): Блокирует и ждет, пока счетчик не обнулится.

Пример:

package main

import (
    "fmt"
    "sync"
    "time"
)

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done() // Уменьшаем счетчик при выходе из функции
    fmt.Printf("Рабочий %d началn", id)
    time.Sleep(time.Second)
    fmt.Printf("Рабочий %d закончилn", id)
}

func main() {
    var wg sync.WaitGroup

    for i := 1; i <= 3; i++ {
        wg.Add(1) // Увеличиваем счетчик перед запуском горутины
        go worker(i, &wg)
    }

    fmt.Println("Основная горутина ждет завершения всех рабочих...")
    wg.Wait() // Блокировка до тех пор, пока счетчик не станет 0
    fmt.Println("Все рабочие завершили выполнение.")
}

Важно: Вызов Done() при счетчике, равном нулю, или уменьшение счетчика до отрицательного значения вызовет панику.