Ответ
Для корректной обработки отмены контекста в горутине используется блокирующий select
с проверкой канала ctx.Done()
. Этот механизм позволяет горутине вовремя прекратить свою работу, освободить ресурсы и избежать утечек.
Основной паттерн:
Канал ctx.Done()
закрывается, когда контекст отменяется (из-за вызова cancel()
, истечения таймаута или дедлайна). Чтение из закрытого канала происходит немедленно.
func worker(ctx context.Context, dataChan <-chan string) error {
for {
select {
case <-ctx.Done():
// Контекст был отменен. Прекращаем работу.
fmt.Println("Worker: context cancelled.")
// Важно вернуть ошибку, чтобы вызывающий код знал причину остановки.
return ctx.Err()
case data, ok := <-dataChan:
if !ok {
// Канал с данными закрыт, работа завершена.
return nil
}
// Выполняем полезную работу с данными
fmt.Printf("Processing data: %sn", data)
time.Sleep(500 * time.Millisecond) // Имитация работы
}
}
}
Ключевые моменты и рекомендации:
Используйте
select
в циклах: В любой долгоживущей горутине, выполняющей работу в цикле,select
является обязательным для проверки отмены.Возвращайте
ctx.Err()
: После получения сигнала изctx.Done()
, проверьтеctx.Err()
. Эта функция вернет причину отмены:context.Canceled
илиcontext.DeadlineExceeded
.Пробрасывайте контекст: Передавайте
context.Context
вниз по стеку вызовов всем функциям, которые могут быть долго выполняющимися или блокирующими (например, HTTP-запросы, запросы к БД).Освобождайте ресурсы: Перед выходом из функции по сигналу отмены убедитесь, что все захваченные ресурсы (файлы, соединения) корректно освобождены, например, с помощью
defer
.