Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Виды контекстов в Go
В Go пакет context предоставляет механизм для передачи deadlines, отмены и других значений, связанных с запросом, через границы API и между горутинами. Основные виды контекстов создаются через функции-конструкторы из пакета context.
1. Пустой контекст - context.Background()
Это корневой контекст, который никогда не отменяется, не имеет дедлайна и не содержит значений. Используется как отправная точка для создания производных контекстов.
ctx := context.Background()
Применение:
- В точке входа программы (main, init)
- В тестах
- Как основа для создания других контекстов
2. Контекст TODO - context.TODO()
Аналогичен Background(), но предназначен для случаев, когда неизвестно, какой контекст использовать, или когда контекст еще не готов.
ctx := context.TODO()
Применение:
- Временно, при рефакторинге кода
- Когда функция требует контекст, но подходящий контекст пока не определен
3. Контекст с отменой - context.WithCancel()
Создает производный контекст, который может быть отменен вызовом функции cancel. При отмене все дочерние контексты также получают сигнал отмены.
ctx, cancel := context.WithCancel(parentContext)
defer cancel() // Важно вызывать cancel для освобождения ресурсов
Применение:
- Управление жизненным циклом горутин
- Прерывание длительных операций по требованию
4. Контекст с таймаутом - context.WithTimeout()
Создает контекст, который автоматически отменяется после истечения указанного времени.
ctx, cancel := context.WithTimeout(parentContext, 5*time.Second)
defer cancel()
Применение:
- HTTP-запросы с ограничением по времени
- Операции БД с таймаутом
- Любые операции, которые не должны выполняться дольше заданного времени
5. Контекст с дедлайном - context.WithDeadline()
Аналогичен WithTimeout(), но отменяется в конкретный момент времени, а не через промежуток.
deadline := time.Date(2024, 12, 31, 23, 59, 59, 0, time.UTC)
ctx, cancel := context.WithDeadline(parentContext, deadline)
defer cancel()
Применение:
- Задачи, которые должны завершиться к определенному сроку
- Планировщики задач
6. Контекст со значениями - context.WithValue()
Создает контекст, который хранит пары ключ-значение. Ключи должны быть сравниваемыми и не должны быть встроенными типами.
type contextKey string
const requestIDKey contextKey = "requestID"
ctx := context.WithValue(parentContext, requestIDKey, "req-123")
Применение:
- Передача метаданных (request ID, user ID, etc.)
- Передача данных между слоями приложения
Важные аспекты работы с контекстами
Правила использования:
- Передавайте контекст как первый параметр функций, которые его используют
- Всегда вызывайте
cancelдля контекстов с отменой, чтобы избежать утечек памяти - Не храните контексты в структурах - передавайте их явно
- Контексты неизменяемы - каждая функция With* возвращает новый контекст
Пример комплексного использования:
func processRequest(ctx context.Context, req *Request) error {
// Создаем контекст с таймаутом для всей операции
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
// Добавляем request ID
ctx = context.WithValue(ctx, requestIDKey, generateID())
// Передаем контекст вниз по стеку вызовов
err := performDatabaseQuery(ctx, req)
if err != nil {
return fmt.Errorf("query failed: %w", err)
}
return nil
}
Отслеживание состояния контекста:
select {
case <-ctx.Done():
return ctx.Err() // Возвращает context.Canceled или context.DeadlineExceeded
case result := <-ch:
return result
}
Контексты в Go являются фундаментальным механизмом для управления параллелизмом, контроля времени выполнения операций и передачи метаданных. Их правильное использование критически важно для создания надежных, отзывчивых и эффективных приложений на Go.