← Назад к вопросам

Какие знаешь виды контекстов?

2.2 Middle🔥 251 комментариев
#Основы Go

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Виды контекстов в 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.)
  • Передача данных между слоями приложения

Важные аспекты работы с контекстами

Правила использования:

  1. Передавайте контекст как первый параметр функций, которые его используют
  2. Всегда вызывайте cancel для контекстов с отменой, чтобы избежать утечек памяти
  3. Не храните контексты в структурах - передавайте их явно
  4. Контексты неизменяемы - каждая функция 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.