Przejdź do głównej treści
eLearner.app
Moduł 7 · Lekcja 5 z 535/50 w kursie~14 min
Lekcje modułu (5/5)

`context.Context`: anulowanie i limity czasu

Pakiet context jest de facto standardem propagacji ** anulowanie, terminy i wartości związane z zakresem** w całym łańcuchu połączeń, w wielu gorutynach. Wszystkie standardowe pakiety „sieciowe”. (net/http, database/sql, os/exec) zaakceptuj context.Context jako ich pierwszy parametr.

Interfejs

Go
type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key any) any
}
  • Done(): kanał zamykany po anulowaniu kontekstu.
  • Err(): powód anulowania (context.Canceled lub context.DeadlineExceeded).
  • Deadline(): termin opcjonalny.
  • Value(): wyszukiwanie wartości związanych z zakresem (używaj oszczędnie).

Cztery podstawowe funkcje

Go
ctx := context.Background()              // radice: usalo in main, init, test
ctx := context.TODO()                    // "non so ancora": stub esplicito

ctx, cancel := context.WithCancel(parent)               // cancel manuale
ctx, cancel := context.WithTimeout(parent, d)           // scadenza relativa
ctx, cancel := context.WithDeadline(parent, t)          // scadenza assoluta

ctx := context.WithValue(parent, key, value)            // valore scope-bound

Wszystkie formularze pochodne zwracają funkcję cancel: zawsze ją wywołuj (najlepiej z defer), aby zwolnić zasoby wewnętrzne, nawet jeśli kontekst już wygasł.

Wzór przekroczenia limitu czasu

Go
func fetchUser(id string) (*User, error) {
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()

    return queryUser(ctx, id)   // queryUser deve rispettare ctx
}

Jeżeli queryUser trwa dłużej niż 2 sekundy, ctx.Done() zostaje zamknięty i funkcja musi przerwać operację.

Przestrzegając kontekstu: wybierz Gotowe()

Go
func slowWork(ctx context.Context) error {
    for {
        select {
        case <-ctx.Done():
            return ctx.Err()      // canceled o deadline exceeded
        case <-time.After(100 * time.Millisecond):
            // un tick di lavoro
        }
    }
}

Zasada: wszędzie tam, gdzie Twoja funkcja może blokować się przez długi czas, należy to zrobić musi obsłużyć ctx.Done(). W przeciwnym razie kontekst jest „włączany”. nic.

Konwencja pierwszego parametru

Go
func Fetch(ctx context.Context, url string) ([]byte, error) { ... }
//        ^^^^^^^^^^^^^^^^^^^
// SEMPRE primo, mai dentro a una struct, mai opzionale
  • ctx ZAWSZE jako pierwszy parametr o nazwie ctx.
  • Nigdy nie umieszczaj Context jako pola struktury (bardzo rzadkie wyjątki).
  • Nigdy nie przekazuj nil: użyj context.TODO() jako kodu pośredniczącego.

kontekst.WithValue: oszczędnie

Go
type userKey struct{}

ctx := context.WithValue(ctx, userKey{}, currentUser)
// più sotto:
if u, ok := ctx.Value(userKey{}).(*User); ok { ... }

Wytyczne:

  • TYLKO dla danych o zakresie żądania (identyfikator żądania, identyfikator śledzenia, tożsamość użytkownika).
  • NIGDY dla parametrów funkcji: przekazuj je normalnie.
  • Klucze niestandardowego, nieeksportowanego typu, aby uniknąć kolizji.

Propagacja wzdłuż łańcucha

Go
func handleHTTP(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()   // context legato al ciclo di vita della richiesta
    user, err := fetchUser(ctx, r.URL.Query().Get("id"))
    if err != nil { ... }
    // ...
}

net/http automatycznie anuluje r.Context(), gdy klient rozłączy się lub gdy przewodnik powróci. Propagując to wszystkim wywołania downstream, całe drzewo operacji zostaje anulowane kaskada: brak niepotrzebnej pracy po rozłączeniu.

Spróbuj

Ćwiczenie#go.m7.l5.e1
Próby: 0Ładowanie...

Utwórz kontekst z 1-sekundowym limitem czasu wyprowadzonym z kontekstu.Background() i pamiętaj o wywołaniu cancel z odroczeniem.

Ładowanie edytora...
Pokaż wskazówkę

KODEF0 zwraca KODEF1; zawsze zadzwoń anuluj.

Rozwiązanie dostępne po 3 próbach

Ćwiczenie#go.m7.l5.e2
Próby: 0Ładowanie...

Użyj <-ctx.Done() w zaznaczeniu, aby poczekać na anulowanie kontekstu.

Ładowanie edytora...
Pokaż wskazówkę

`ctx.Done()` to kanał, który zamyka się, gdy kontekst zostaje anulowany.

Rozwiązanie dostępne po 3 próbach

Quiz#go.m7.l5.e3
Gotowe

Zgodnie z konwencją, gdzie w sygnaturze funkcji znajduje się parametr ctx?

Go
func Fetch(???, url string) ([]byte, error)
Opcje odpowiedzi

Podsumowanie

  • context.Context propaguje wartości anulowania, terminu i zakresu.
  • Background()/TODO() jako korzeń; WithCancel/WithTimeout/WithDeadline do wyprowadzenia.
  • Zawsze defer cancel(), aby zwolnić zasoby.
  • Funkcje „długie” muszą mieć select na ctx.Done() lub przekazywać ctx do standardowych pakietów.
  • Konwencja: ctx jako PIERWSZY parametr, nigdy wewnątrz struktury.
  • Background()0 tylko dla danych o zakresie żądania (identyfikator żądania, identyfikator śledzenia).
  • W Background()1, Background()2 jest anulowane w przypadku rozłączenia klienta.