Ответ
Механизм контекста в Go реализуется через интерфейс context.Context
. Он предназначен для передачи сигналов отмены (cancellation), дедлайнов и других request-scoped значений через границы API и между горутинами.
Интерфейс context.Context
определяет четыре метода:
type Context interface {
// Deadline возвращает время, когда работа, связанная с этим контекстом,
// должна быть отменена. ok=false, если дедлайн не установлен.
Deadline() (deadline time.Time, ok bool)
// Done возвращает канал, который закрывается, когда работа
// должна быть отменена. Канал Done может вернуть nil.
Done() <-chan struct{}
// Err возвращает причину отмены контекста.
// Возвращает context.Canceled или context.DeadlineExceeded.
Err() error
// Value возвращает значение, ассоциированное с ключом,
// или nil, если такого ключа нет.
Value(key any) any
}
Основные способы создания контекста:
context.Background()
: Базовый, пустой контекст. Обычно используется вmain()
или на верхнем уровне обработки запроса.context.TODO()
: Используется как заглушка, когда неясно, какой контекст использовать.context.WithCancel(parent)
: Создает контекст, который можно отменить вручную.context.WithTimeout(parent, duration)
: Создает контекст, который отменится по истечении таймаута.context.WithValue(parent, key, value)
: Добавляет в контекст пару ключ-значение.
Пример использования:
Функция, которая прекращает свою работу при отмене контекста.
func operation(ctx context.Context) {
select {
case <-time.After(5 * time.Second):
fmt.Println("Операция завершена успешно")
case <-ctx.Done(): // Канал закрылся, контекст отменен
fmt.Println("Операция отменена:", ctx.Err())
}
}
func main() {
// Создаем контекст, который отменится через 2 секунды
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel() // Важно вызывать cancel для освобождения ресурсов
operation(ctx) // Выведет: "Операция отменена: context deadline exceeded"
}