Lektionen des Moduls (5/5)
`context.Context`: Abbruch und Deadlines
Das context-Paket ist der De-facto-Standard für die Weitergabe
Kündigung, Fristen und Umfangswerte** entlang der Anrufkette,
über mehrere Goroutinen hinweg. Alle Standard-Netzwerkpakete
(net/http, database/sql, os/exec) akzeptieren einen context.Context als
ihr erster Parameter.
Die Schnittstelle
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key any) any
}Done(): Kanal, der geschlossen wird, wenn der Kontext abgebrochen wird.Err(): Grund für die Stornierung (context.Canceledodercontext.DeadlineExceeded).Deadline(): optionale Frist.Value(): Suche nach bereichsgebundenen Werten (sparsam verwenden).
Die vier Grundfunktionen
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-boundAlle abgeleiteten Formen geben eine cancel-Funktion zurück: Rufen Sie sie immer auf
(idealerweise mit defer), um interne Ressourcen freizugeben, auch wenn die
Der Kontext ist bereits abgelaufen.
Timeout-Muster
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
}Wenn queryUser länger als 2 Sekunden dauert, wird ctx.Done() geschlossen und
Die Funktion muss den Vorgang abbrechen.
Respektieren Sie den Kontext: Wählen Sie „Done()“ aus.
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
}
}
}Die Regel: Überall dort, wo Ihre Funktion für längere Zeit blockieren könnte, wird sie verwendet muss mit ctx.Done() umgehen. Andernfalls ist der Kontext „eingeschaltet“. nichts.
Konvention für den ersten Parameter
func Fetch(ctx context.Context, url string) ([]byte, error) { ... }
// ^^^^^^^^^^^^^^^^^^^
// SEMPRE primo, mai dentro a una struct, mai opzionalectxIMMER als erster Parameter mit dem Namenctx.- Niemals
Contextals Feld einer Struktur einfügen (sehr seltene Ausnahmen). - Niemals
nilübergeben: Verwenden Siecontext.TODO()als Stub.
context.WithValue: sparsam
type userKey struct{}
ctx := context.WithValue(ctx, userKey{}, currentUser)
// più sotto:
if u, ok := ctx.Value(userKey{}).(*User); ok { ... }Richtlinien:
- NUR für anforderungsbezogene Daten (Anfrage-ID, Trace-ID, Benutzeridentität).
- NIEMALS für Funktionsparameter: Übergeben Sie sie normal.
- Schlüssel vom Typ benutzerdefinierter, nicht exportierter, um Kollisionen zu vermeiden.
Ausbreitung entlang der Kette
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 bricht r.Context() automatisch ab, wenn der Client
die Verbindung unterbrochen wird oder wenn der Handler zurückkehrt. Indem man es an alle weitergibt
Bei nachgeschalteten Aufrufen wird der gesamte Operationsbaum abgebrochen
Kaskade: Keine verschwendete Arbeit nach der Trennung.
Probieren Sie es aus
Erstellen Sie einen Kontext mit einem von context.Background() abgeleiteten Timeout von 1 Sekunde und denken Sie daran, cancel mit defer aufzurufen.
Hinweis anzeigen
`context.WithTimeout(parent, d)` gibt `(ctx, cancel)` zurück; Rufen Sie immer abbrechen an.
Lösung nach 3 Versuchen verfügbar
Verwenden Sie <-ctx.Done() in einer Auswahl, um darauf zu warten, dass der Kontext abgebrochen wird.
Hinweis anzeigen
`ctx.Done()` ist ein Kanal, der geschlossen wird, wenn der Kontext abgebrochen wird.
Lösung nach 3 Versuchen verfügbar
Wo steht der ctx-Parameter konventionsgemäß in einer Funktionssignatur?
func Fetch(???, url string) ([]byte, error)Zusammenfassung
– context.Context gibt Stornierungs-, Frist- und bereichsgebundene Werte weiter.
Background()/TODO()als Wurzel;WithCancel/WithTimeout/WithDeadlineabzuleiten.- Immer
defer cancel(), um Ressourcen freizugeben. - „Lange“ Funktionen müssen
selectaufctx.Done()oder ctx an Standardpakete übergeben. - Konvention:
ctxals ERSTER Parameter, niemals innerhalb einer Struktur. –Background()0 nur für anforderungsbezogene Daten (Anfrage-ID, Trace-ID). – InBackground()1 wirdBackground()2 beim Trennen des Clients abgebrochen.