Интерфейс context.Context

Интерфейс context.Context является фундаментальным механизмом в Go для управления жизненным циклом операций, выполняющихся в горутинах. Он предоставляет возможность передачи сигналов отмены, установки дедлайнов и таймаутов, а также передачи данных между функциями и горутинами. Контекст обычно создается в корневых функциях и передается вниз по цепочке вызовов, обеспечивая единое управление для всех связанных операций.

Основными методами интерфейса являются Deadline, который возвращает время, когда контекст должен быть отменен, Done, который возвращает канал, закрываемый при отмене контекста, Err, возвращающий причину отмены, и Value, позволяющий получать значения по ключу.

Синтаксис

Интерфейс context.Context определяется следующими методами:

gotype Context interface {
  Deadline() (deadline time.Time, ok bool)
  Done() <-chan struct{}
  Err() error
  Value(key any) any
}

Пример с базовым использованием

Давайте создадим контекст с таймаутом и проверим его методы:

gopackage main

import (
  "context"
  "fmt"
  "time"
)

func main() {
  ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
  defer cancel()

  deadline, ok := ctx.Deadline()
  if ok {
    fmt.Println("Deadline:", deadline.Format("15:04:05"))
  }
}

Результат выполнения кода:

go"Deadline: 14:35:12"

Пример с отменой контекста

Покажем, как использовать метод Done для получения сигнала отмены:

gopackage main

import (
  "context"
  "fmt"
  "time"
)

func main() {
  ctx, cancel := context.WithCancel(context.Background())

  go func() {
    select {
    case <-ctx.Done():
      fmt.Println("Context cancelled")
      fmt.Println("Error:", ctx.Err())
    }
  }()

  time.Sleep(100 * time.Millisecond)
  cancel()
  time.Sleep(100 * time.Millisecond)
}

Результат выполнения кода:

go"Context cancelled"
"Error: context canceled"

Пример с передачей данных

Используем метод Value для передачи данных через контекст:

gopackage main

import (
  "context"
  "fmt"
)

type key string

func main() {
  ctx := context.WithValue(context.Background(), key("userID"), 12345)

  value := ctx.Value(key("userID"))
  fmt.Println("User ID:", value)
}

Результат выполнения кода:

go"User ID: 12345"

Пример с проверкой ошибки

Метод Err возвращает ошибку после отмены контекста:

gopackage main

import (
  "context"
  "fmt"
  "time"
)

func main() {
  ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
  defer cancel()

  time.Sleep(2 * time.Second)

  err := ctx.Err()
  fmt.Println("Context error:", err)
}

Результат выполнения кода:

go"Context error: context deadline exceeded"

Смотрите также

  • функцию context.Background,
    которая возвращает пустой корневой контекст
  • функцию context.WithTimeout,
    которая создает контекст с таймаутом
  • функцию context.WithCancel,
    которая создает контекст с функцией отмены
  • функцию context.WithValue,
    которая добавляет данные в контекст