Ответ
context.Context в Go — это стандартный механизм для передачи дедлайнов, сигналов отмены и других данных (request-scoped values) между горутинами. Он является неотъемлемой частью написания надежного и управляемого конкурентного кода, особенно в сетевых сервисах и распределенных системах.
Основные сценарии использования:
Отмена (Cancellation): Если пользователь отменил запрос (например, закрыл вкладку браузера),
contextпозволяет каскадно передать сигнал отмены всем горутинам, которые обрабатывали этот запрос (например, запросы к БД, другим сервисам), чтобы они прекратили работу и освободили ресурсы.- Создается с помощью
context.WithCancel(). - Проверяется через канал
<-ctx.Done().
- Создается с помощью
Таймауты и Дедлайны (Timeouts and Deadlines): Можно установить максимальное время на выполнение операции. Если время истекло, контекст будет отменен. Это критически важно для предотвращения "зависания" горутин в ожидании ответа от медленного внешнего сервиса.
- Создается с помощью
context.WithTimeout()илиcontext.WithDeadline().
- Создается с помощью
Передача данных (Value Propagation): Позволяет передавать данные вниз по стеку вызовов, например, ID запроса, информацию для трассировки или данные о пользователе.
- Создается с помощью
context.WithValue(). - Важно: Считается плохой практикой использовать
WithValueдля передачи обязательных параметров функции. Параметры должны передаваться явно. Контекст предназначен только для сквозных, request-scoped данных.
- Создается с помощью
Пример с таймаутом:
package main
import (
"context"
"fmt"
"time"
)
func longOperation(ctx context.Context) {
select {
case <-time.After(3 * 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, чтобы освободить ресурсы
longOperation(ctx) // Операция будет прервана через 2 секунды
}Правила использования Context:
- Передавайте
Contextкак первый аргумент функции, с именемctx. - Никогда не храните
Contextвнутри структуры. Передавайте его явно в каждый вызов. - Цепочка вызовов должна пробрасывать контекст дальше.
- Никогда не передавайте
nilContext. Если не уверены, какой использовать, используйтеcontext.Background().