Ответ
Пакет context
в Go предназначен для управления отменой операций, передачей данных в рамках запроса и установкой дедлайнов. Функция context.WithTimeout
— это один из ключевых инструментов для контроля времени выполнения операций.
Назначение:
context.WithTimeout
создает дочерний контекст, который автоматически отменяется по истечении заданного таймаута. Это критически важно для предотвращения "зависания" горутин при выполнении долгих операций, таких как:
- Сетевые запросы (HTTP, gRPC)
- Обращения к базе данных
- Любые другие блокирующие вызовы
Пример использования:
package main
import (
"context"
"fmt"
"time"
)
func main() {
// Создаем родительский контекст
parentCtx := context.Background()
// Создаем дочерний контекст с таймаутом в 50 миллисекунд
ctx, cancel := context.WithTimeout(parentCtx, 50*time.Millisecond)
// defer cancel() гарантирует, что ресурсы контекста будут освобождены,
// даже если операция завершится до истечения таймаута.
defer cancel()
select {
case <-time.After(100 * time.Millisecond): // Эта операция заведомо дольше таймаута
fmt.Println("Операция успешно завершена (не должно произойти)")
case <-ctx.Done(): // Канал Done() закрывается при отмене контекста
// ctx.Err() объясняет причину отмены
fmt.Println("Операция прервана по таймауту:", ctx.Err()) // Выведет: context deadline exceeded
}
}
Ключевые практики и нюансы:
- Обязательный вызов
cancel()
: Всегда вызывайте функциюcancel
, возвращаемуюcontext.WithTimeout
, чтобы освободить связанные с контекстом ресурсы. Лучшая практика — использоватьdefer cancel()
сразу после создания контекста. - Проверка
ctx.Err()
: После получения сигнала изctx.Done()
, проверьтеctx.Err()
, чтобы узнать причину отмены. ДляWithTimeout
это будетcontext.DeadlineExceeded
. - Передача контекста: Контекст следует передавать как первый аргумент в функции, которые могут быть долго выполняющимися. Это общепринятое соглашение в Go.
- Иерархия контекстов: Отмена родительского контекста каскадно отменяет все его дочерние контексты. Таймаут дочернего контекста не может превышать дедлайн родительского.