Назад к вопросам
Middle
104
questionbank
Расскажи о случаях использования контекста в Go.
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Контекст в Go используется для управления жизненным циклом запросов и контроля выполнения горутин. Основные случаи применения:
- Отмена: Позволяет отменить выполнение цепочки горутин, связанной с определенным запросом. Например, при закрытии соединения или по таймауту.
- Таймаут: Устанавливает крайний срок выполнения операции. Если операция не завершается в срок, контекст отменяется. Это предотвращает бесконечное ожидание.
- Передача запросо-специфичных данных: Позволяет передавать данные, относящиеся к конкретному запросу (например, ID пользователя, идентификатор трассировки), через цепочку вызовов функций без изменения их сигнатур.
Примеры использования:
-
Отмена по сигналу:
package main import ( "context" "fmt" "time" ) func worker(ctx context.Context, id int) { for { select { case <-ctx.Done(): fmt.Printf("Worker %d interrupted\n", id) return default: fmt.Printf("Worker %d working...\n", id) time.Sleep(500 * time.Millisecond) } } } func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Гарантируем отмену go worker(ctx, 1) go worker(ctx, 2) time.Sleep(2 * time.Second) cancel() // Отменяем контекст time.Sleep(500 * time.Millisecond) // Даем время горутинам завершиться } -
Таймаут:
package main import ( "context" "fmt" "time" ) func longOperation(ctx context.Context) error { select { case <-time.After(3 * time.Second): // Имитация долгой работы fmt.Println("Operation completed successfully") return nil case <-ctx.Done(): fmt.Println("Operation cancelled by context:", ctx.Err()) return ctx.Err() } } func main() { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() err := longOperation(ctx) if err != nil { fmt.Println("Error:", err) } } -
Передача данных:
package main import ( "context" "fmt" ) type UserKey string const userIDKey UserKey = "userID" func processRequest(ctx context.Context) { userID := ctx.Value(userIDKey).(int) fmt.Printf("Processing request for user ID: %d\n", userID) // Дальнейшая обработка запроса с использованием userID } func main() { ctx := context.WithValue(context.Background(), userIDKey, 123) processRequest(ctx) }
Важно использовать context.Background() или context.TODO() в качестве корневого контекста и передавать его вниз по цепочке вызовов. Не следует хранить контекст в структурах данных, если он не связан напрямую с жизненным циклом этой структуры.