Корректное завершение
Корректно останавливайте работников
«Корректное завершение» — бесплатный урок Go Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Go Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Go Academy содержит 4 уроков всего.
Зачем нужно корректное завершение
Долгоживущим горутинам нужно сообщить, когда остановиться. Корректное завершение позволяет worker закончить текущую работу, освободить ресурсы и завершиться без утечек или потери данных.
- Нет утечек горутин
- Нет незавершённых записей
- Процесс завершается чисто
Шаблон канала done
Классический подход — канал done. Его закрытие рассылает сигнал остановки всем горутинам, которые его слушают, поскольку чтение из закрытого канала завершается немедленно.
done := make(chan struct{})
// ... later
close(done)select для сигналов Stop
Worker использует select, чтобы либо обработать задачу, либо заметить канал done. Когда done закрывается, срабатывает соответствующая ветвь, и worker возвращается.
for {
select {
case <-done:
return
case j := <-jobs:
process(j)
}
}Контекст context.Context
Современный идиоматичный инструмент — context. context.WithCancel предоставляет контекст и функцию отмены. Вызов cancel закрывает канал Done контекста.
ctx, cancel := context.WithCancel(context.Background())
defer cancel()Ожидание на ctx.Done()
Worker выполняют выбор в ctx.Done(). Когда вызывается cancel или истекает крайний срок, канал закрывается и worker завершается.
select {
case <-ctx.Done():
return ctx.Err()
case j := <-jobs:
process(j)
}Ожидание завершения worker
Одного сигнала остановки недостаточно: необходимо дождаться фактического завершения worker. Объект sync.WaitGroup отслеживает их, чтобы main мог заблокироваться до обнуления счётчика.
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
runWorker(ctx)
}()
// ... later
cancel()
wg.Wait()Тайм-ауты с помощью context
context.WithTimeout автоматически отменяет контекст по истечении заданного времени. Это ограничивает продолжительность завершения, прежде чем потребуется принудительно завершить процесс.
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()Полное корректное завершение
Эта программа запускает два worker, отменяет контекст и ждёт чистого завершения обоих, прежде чем напечатать done.
package main
import (
"context"
"fmt"
"sync"
"time"
)
func worker(ctx context.Context, id int, wg *sync.WaitGroup) {
defer wg.Done()
for {
select {
case <-ctx.Done():
fmt.Printf("worker %d stopping\n", id)
return
case <-time.After(50 * time.Millisecond):
}
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
var wg sync.WaitGroup
for i := 1; i <= 2; i++ {
wg.Add(1)
go worker(ctx, i, &wg)
}
time.Sleep(120 * time.Millisecond)
cancel()
wg.Wait()
fmt.Println("all workers stopped")
}Завершение текущей работы
При завершении часто требуется, чтобы worker закончили уже начатую работу. Прочитайте оставшиеся задачи в последнем цикле или перестаньте принимать новые задачи, позволив текущим завершиться.
Перехват сигналов OS
В настоящих серверах signal.NotifyContext связывает отмену с SIGINT и SIGTERM. После нажатия Ctrl+C запускается тот же путь корректного завершения, что и при ручной отмене.
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()Не забывайте cancel()
Всегда используйте defer cancel(), даже при использовании WithTimeout. Если не вызвать cancel, внутренняя горутина и таймер контекста будут оставаться активными до истечения крайнего срока.
Быстрая проверка
Проверьте, насколько хорошо Вы понимаете корректное завершение.
Итоги
Вы изучили корректное завершение:
- Используйте context.WithCancel или канал done для сигнала остановки
- Worker выполняют выбор на ctx.Done()
- WaitGroup гарантирует фактическое завершение всех worker
- Связывайте отмену с сигналами OS в настоящих серверах
- Всегда используйте defer cancel()
Часто задаваемые вопросы
Урок «Корректное завершение» бесплатный?
Да — полный текст урока «Корректное завершение» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Go Academy, подпишись на CoddyKit PRO. Курс Go Academy содержит 4 уроков всего.
Чему я научусь в уроке «Корректное завершение»?
Корректно останавливайте работников Ты практикуешь Go Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Go Academy?
Предыдущий опыт не требуется. Go Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Корректное завершение»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Go Academy?
Да. Каждый урок Go Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Паттерн пула работников
- Fan-Out и Fan-In
- Этапы конвейера
- Корректное завершение