Стендап Сьогодні 📢 Канал в Telegram @stendap_sogodni

🤖🚫 Контент вільний від AI. Цей пост на 100% написаний людиною, як і все на моєму блозі. Насолоджуйтесь!

14.06.2023

WaitGroup в Go

Для закінчення питання, поставленого вчора, не вистачає ще однієї частини. Ну, добре, зробили ми архітектуру на контекстах, контекст сплинув, горутіни отримали сигнал зупинки. Що далі? Необхідно дочекатись, доки всі горутіни завершать свою роботу. Особливо якщо зупиняємо всю програму — якщо не чекати, то немає сенсу навіть ввічливо попереджати горутіни про зупинку.

Можна знову придумати свою систему з каналами, і так далі. А можна взяти стандартний тип sync.WaitGroup, який створений саме для того, щоб чекати зупинки декількох горутін. Від банального лічильника його відрізняє наявність методу Wait(), який буде чекати, поки всі горутіни не викликають метод Done().

Тобто алгоритм таких: на початку підраховуємо кількість горутін, які запускаємо, та заряджаємо викликом wg.Add(). Далі, кожна горутіна по завершенню викликає wg.Done(). Нарешті, головна горутіна спочатку сигналізує про завершення контексту, а потім викликає wg.Wait().

Чи не надто витратно створювати WaitGroup для довготривалих процесів? Ні, цей тип містить лише 2 цілих числа, та не має “живого” коду. Взагалі це просто лічильник + семафор, нічого магічного. Це добре, бо нам потрібно передати WaitGroup в кожну горутіну, яку ми запускаємо.

Як чекати з обмеженням по часу? Це типова задача — наприклад, ми знаємо, що через 60 секунд після отримання сигналу наш процес буде вбитий оркестрантом. Відповідь така: обмеження треба обробляти ще всередині горутін. Що це значить на практиці — залежить від конкретного випадку. Але ми точно повинні не кидати горутіни у невизначеному стані, як воно буде, якщо тайм-аут спрацює назовні.

Такий підхід набагато простіше, ніж спостерігати за спустошенням каналів з чергами або вигадувати ще якийсь механізм очікування.