Ответ
context.WithCancel
— это функция из стандартной библиотеки Go, которая создает и возвращает дочерний контекст вместе с функцией для его отмены (CancelFunc
).
Основное назначение — управлять жизненным циклом горутин, предоставляя возможность грациозно их остановить.
Как это работает:
- Вы создаете контекст с возможностью отмены:
ctx, cancel := context.WithCancel(parentCtx)
. - Вы передаете
ctx
в горутины, которые должны быть управляемыми. - Внутри горутин вы используете
select
для прослушивания каналаctx.Done()
. - Когда вызывается функция
cancel()
, каналctx.Done()
закрывается. Это служит сигналом для всех горутин, слушающих этот канал, что им пора завершать работу.
Пример:
func main() {
// Создаем контекст, который можно отменить
ctx, cancel := context.WithCancel(context.Background())
go func(ctx context.Context) {
fmt.Println("Горутина запущена...")
select {
case <-time.After(5 * time.Second): // Имитация долгой работы
fmt.Println("Операция успешно завершена")
case <-ctx.Done(): // Ожидание сигнала отмены
fmt.Println("Операция отменена по сигналу контекста")
// Здесь может быть логика очистки ресурсов
}
}(ctx)
// Даем горутине поработать 1 секунду
time.Sleep(1 * time.Second)
fmt.Println("Отправляем сигнал отмены...")
cancel() // Отменяем контекст
time.Sleep(1 * time.Second) // Ждем, чтобы горутина успела завершиться
fmt.Println("Программа завершена")
}
Ключевые моменты и лучшие практики:
- Всегда вызывайте
cancel()
: Чтобы избежать утечек ресурсов, всегда вызывайте функциюcancel
, даже если операция завершилась успешно. Лучшая практика — использоватьdefer cancel()
сразу после создания контекста. - Пропаганда отмены: Отмена родительского контекста автоматически отменяет все дочерние контексты, созданные на его основе. Это позволяет каскадно завершать целые деревья операций.
- Не только для отмены: Контекст также используется для передачи данных между вызовами в рамках одного запроса (например, ID запроса или данные аутентификации) с помощью
context.WithValue
.