Jak jsou strukturovány kontexty v jazyce Go?
sobes.tech AI
Odpověď od AI
context (context.Context) v Go se používá k přenosu informací o časových limitech, zrušeních a dalších údajích mezi API hranicemi. Představuje strom: každý kontext je potomkem jiného, kromě kořenového (context.Background() nebo context.TODO()).
Hlavní metody rozhraní context.Context:
Deadline() (deadline time.Time, ok bool): Vrací časový limit kontextu.Done() <-chan struct{}: Vrací kanál, který se uzavře při zrušení kontextu.Err() error: Vrací chybu, která vedla ke zrušení kontextu.Value(key any) any: Vrací hodnotu spojenou s klíčem v kontextu.
Vytváří se pomocí funkcí balíčku context:
context.Background(): Kořenový prázdný kontext, používá se jako základ hlavního procesu.context.TODO(): Používá se jako dočasná náhrada, když není známo, jaký kontext použít.context.WithCancel(parent Context): Vytváří podřízený kontext a funkci zrušení.context.WithDeadline(parent Context, d time.Time): Vytváří podřízený kontext s časovým limitem.context.WithTimeout(parent Context, timeout time.Duration): Vytváří podřízený kontext s časovým limitem.context.WithValue(parent Context, key, val any): Vytváří podřízený kontext s hodnotou.
Hlavní implementace Context:
emptyCtx: Základní, nezrušitelný a bez hodnot. Používá seBackgroundaTODO.cancelCtx: Podporuje zrušení. Skládá se ze základního kontextu a kanálu zrušení.timerCtx: Podporuje časový limit / časovač. ObsahujecancelCtxa časovač.valueCtx: Podporuje přenos hodnot. Obsahuje základní kontext a klíč-hodnotu.
Při zrušení rodičovského kontextu jsou automaticky zrušeny všechny jeho potomci. To umožňuje šíření signálů zrušení nebo časových limitů řetězcem volání.
Příklad použití context.WithCancel:
package main
import (
"context"
"fmt"
"time"
)
func main() {
// Vytvoření kořenového kontextu a funkce zrušení
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // Zajišťuje zrušení při ukončení main
go func() {
select {
case <-ctx.Done(): // Čeká na zrušení kontextu
fmt.Println("Úloha zrušena:", ctx.Err())
return
case <-time.After(5 * time.Second): // Nebo skončí za 5 sekund
fmt.Println("Úloha dokončena")
}
}()
// Zrušení kontextu z jiného místa
time.Sleep(1 * time.Second)
fmt.Println("Zrušení kontextu...")
cancel()
// Dáváme čas gorutině zpracovat zrušení
time.Sleep(100 * time.Millisecond)
}
Příklad použití context.WithValue:
package main
import (
"context"
"fmt"
)
type userIDKey string
func processRequest(ctx context.Context) {
if userID, ok := ctx.Value(userIDKey("UserID")).(string); ok {
fmt.Println("Zpracování požadavku pro User ID:", userID)
} else {
fmt.Println("User ID nebylo nalezeno v kontextu")
}
}
func main() {
ctx := context.WithValue(context.Background(), userIDKey("UserID"), "12345")
processRequest(ctx)
}
Kontexty jsou bezpečné pro vlákna a neměnné, což je důležité pro konkurenční kód. Nejsou určeny k přenosu nestrukturovaných parametrů funkce, ale spíše k metainformacím ovlivňujícím provádění procesu.