Sobes.tech
Middle

Ako sú štruktúrované kontexty v jazyku Go?

sobes.tech AI

Odpoveď od AI

context (context.Context) v Go sa používa na prenos informácií o lehotách, zrušeniach a ďalších údajoch medzi hranicami API. Predstavuje strom: každý kontext je dcérskym prvkom iného, okrem koreňového (context.Background() alebo context.TODO()).

Hlavné metódy rozhrania context.Context:

  • Deadline() (deadline time.Time, ok bool): Vráti časový limit kontextu.
  • Done() <-chan struct{}: Vráti kanál, ktorý sa zatvorí pri zrušení kontextu.
  • Err() error: Vráti chybu, ktorá viedla k zrušeniu kontextu.
  • Value(key any) any: Vráti hodnotu spojenú s kľúčom v kontexte.

Vytvárajú sa pomocou funkcií balíka context:

  • context.Background(): Koreňový prázdny kontext, používa sa ako základ pre hlavný proces.
  • context.TODO(): Používa sa ako dočasná náhrada, keď nie je známe, ktorý kontext použiť.
  • context.WithCancel(parent Context): Vytvára dcérsky kontext a funkciu na zrušenie.
  • context.WithDeadline(parent Context, d time.Time): Vytvára dcérsky kontext s časovým limitom.
  • context.WithTimeout(parent Context, timeout time.Duration): Vytvára dcérsky kontext s časovým limitom.
  • context.WithValue(parent Context, key, val any): Vytvára dcérsky kontext s hodnotou.

Hlavné implementácie Context:

  • emptyCtx: Základný, nezrušiteľný a bez hodnôt. Používajú sa Background a TODO.
  • cancelCtx: Podporuje zrušenie. Skladá sa zo základného kontextu a kanála na zrušenie.
  • timerCtx: Podporuje časový limit / časovač. Obsahuje cancelCtx a časovač.
  • valueCtx: Podporuje prenos hodnôt. Obsahuje základný kontext a kľúč-hodnotu.

Pri zrušení rodičovského kontextu sú automaticky zrušené všetky jeho dcérske. To umožňuje šírenie signálov zrušenia alebo časových limitov cez reťazec volaní.

Príklad použitia context.WithCancel:

package main

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

func main() {
	// Vytvorenie koreňového kontextu a funkcie na zrušenie
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel() // Zabezpečí zrušenie pri ukončení main

	go func() {
		select {
		case <-ctx.Done(): // Čaká na zrušenie kontextu
			fmt.Println("Úloha zrušená:", ctx.Err())
			return
		case <-time.After(5 * time.Second): // Ale skončí za 5 sekúnd
			fmt.Println("Úloha dokončená")
		}
	}()

	// Zrušenie kontextu z iného miesta
	time.Sleep(1 * time.Second)
	fmt.Println("Zrušenie kontextu...")
	cancel()

	// Dávame čas goroutine spracovať zrušenie
	time.Sleep(100 * time.Millisecond)
}

Príklad použitia 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("Spracovanie požiadavky pre User ID:", userID)
	} else {
		fmt.Println("User ID nenájdené v kontexte")
	}
}

func main() {
	ctx := context.WithValue(context.Background(), userIDKey("UserID"), "12345")
	processRequest(ctx)
}

Kontexty sú bezpečné pre vlákna a nemenné, čo je dôležité pre konkurenčný kód. Nie sú určené na prenos nestrukturovaných parametrov funkcie, ale skôr na meta-informácie, ktoré ovplyvňujú vykonávanie procesu.