Sobes.tech
Junior

Czym jest kontekst w Go?

sobes.tech AI

Odpowiedź od AI

Kontekst (context.Context) w Go jest obiektem, który przenosi termin końcowy, sygnał anulowania (cancellation signal) oraz dane specyficzne dla żądania. Używa się go do zarządzania cyklem życia goroutine'ów i przekazywania informacji między nimi podczas wykonywania żądania/operacji.

Główne cechy:

  • Bezpieczny dla współbieżności: Może być bezpiecznie przekazywany między goroutine'ami.
  • Niezmienny: Po utworzeniu, Context nie może być zmieniany. Konteksty pochodne są tworzone na podstawie rodzica.
  • Hierarchiczny: Konteksty tworzą drzewo z korzeniem (context.Background() lub context.TODO()). Anulowanie kontekstu nadrzędnego powoduje anulowanie wszystkich jego potomków.

Główne funkcje pakietu context:

  • context.Background() : Pusty kontekst, zwykle używany w funkcji main, w wysokopoziomowych żądaniach lub podczas testów. Nigdy nie jest anulowany.
  • context.TODO() : Również pusty kontekst. Używany jako zastępczy, gdy nie wiadomo, którego kontekstu użyć, lub gdy funkcjonalność kontekstu jeszcze nie jest zaimplementowana.
  • context.WithCancel(parent Context) : Zwraca nowy kontekst potomny i funkcję anulowania. Wywołanie funkcji anulowania anuluje ten kontekst i wszystkie jego konteksty potomne.
  • context.WithDeadline(parent Context, deadline time.Time) : Zwraca kontekst potomny, który automatycznie jest anulowany, gdy osiągnięty zostanie określony czas. Zwraca również funkcję anulowania do ręcznego anulowania.
  • context.WithTimeout(parent Context, timeout time.Duration) : To samo co WithDeadline, ale z określeniem czasu trwania.
  • context.WithValue(parent Context, key, val interface{}) : Zwraca kontekst potomny z przypisaną wartością do klucza.

Zastosowania:

  • Anulowanie operacji: Na przykład, timeout żądania HTTP lub przerwanie długotrwałej operacji.
  • Przekazywanie danych: Na przykład, ID żądania do logowania, informacje o uwierzytelnianiu.

Przykład użycia context.WithTimeout:

package main

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

func longRunningOperation(ctx context.Context, resultChan chan string) {
	select {
	case <-time.After(3 * time.Second):
		// Operacja zakończyła się sukcesem
		resultChan <- "Operacja zakończona"
	case <-ctx.Done():
		// Kontekst został anulowany
		err := ctx.Err() // Uzyskujemy przyczynę anulowania
		resultChan <- fmt.Sprintf("Operacja anulowana: %v", err)
	}
}

func main() {
	// Tworzymy kontekst z czasem oczekiwania 2 sekundy
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel() // Zapewniamy wywołanie funkcji anulującej

	resultChan := make(chan string, 1)

	go longRunningOperation(ctx, resultChan)

	// Czekamy na wynik lub anulowanie
	select {
	case res := <-resultChan:
		fmt.Println(res)
	case <-ctx.Done():
		fmt.Printf("Główny kontekst zakończył się: %v\n", ctx.Err())
	}

	// Czekamy trochę, aby goroutine mogła się zakończyć, jeśli została anulowana
	time.Sleep(1 * time.Second)
}

W tym przykładzie, longRunningOperation sprawdza, czy kontekst został anulowany. Jeśli czas oczekiwania głównego kontekstu (2 sekundy) upłynie wcześniej niż zakończy się sama operacja (3 sekundy), goroutine otrzymuje sygnał anulowania przez ctx.Done() i kończy się.