Sobes.tech
Middle

Kaip struktūruoti kontekstai Go kalboje?

sobes.tech AI

Atsakymas iš AI

context (context.Context) Go kalboje naudojamas informacijos perdavimui apie terminus, atšaukimus ir kitus duomenis tarp API ribų. Jis vaizduojamas kaip medis: kiekvienas kontekstas yra kito vaikas, išskyrus šaknį (context.Background() arba context.TODO()).

Pagrindiniai context.Context sąsajos metodai:

  • Deadline() (deadline time.Time, ok bool): Grąžina konteksto terminą.
  • Done() <-chan struct{}: Grąžina kanalą, kuris užsidaro, kai kontekstas atšaukiamas.
  • Err() error: Grąžina klaidą, kuri lėmė konteksto atšaukimą.
  • Value(key any) any: Grąžina reikšmę, susijusią su raktu kontekste.

Sukuriama naudojant context paketo funkcijas:

  • context.Background(): Šakninis tuščias kontekstas, naudojamas kaip pagrindas pagrindiniam procesui.
  • context.TODO(): Naudojamas kaip laikina vieta, kai nežinoma, kurį kontekstą naudoti.
  • context.WithCancel(parent Context): Sukuria vaikų kontekstą ir atšaukimo funkciją.
  • context.WithDeadline(parent Context, d time.Time): Sukuria vaikų kontekstą su terminu.
  • context.WithTimeout(parent Context, timeout time.Duration): Sukuria vaikų kontekstą su laiko limitu.
  • context.WithValue(parent Context, key, val any): Sukuria vaikų kontekstą su reikšme.

Pagrindinės Context įgyvendinimai:

  • emptyCtx: Pagrindinis, neatskiriamas ir be reikšmių. Naudojami Background ir TODO.
  • cancelCtx: Palaiko atšaukimą. Sudarytas iš pagrindinio konteksto ir atšaukimo kanalo.
  • timerCtx: Palaiko terminą / laikmatį. Turi cancelCtx ir laikmatį.
  • valueCtx: Palaiko reikšmių perdavimą. Turi pagrindinį kontekstą ir raktas-reikšmė porą.

Kai tėvų kontekstas atšaukiamas, automatiškai atšaukiami visi jo vaikai. Tai leidžia plisti atšaukimo signalus arba terminus per kvietimų grandinę.

Pavyzdys naudojant context.WithCancel:

package main

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

func main() {
	// Sukuriamas pagrindinis kontekstas ir atšaukimo funkcija
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel() // Garantuoja atšaukimą išėjimo metu

	go func() {
		select {
		case <-ctx.Done(): // Laukia konteksto atšaukimo
			fmt.Println("Užduotis atšaukta:", ctx.Err())
			return
		case <-time.After(5 * time.Second): // Arba baigiasi po 5 sekundžių
			fmt.Println("Užduotis įvykdyta")
		}
	}()

	// Atšaukia kontekstą iš kitos vietos
	time.Sleep(1 * time.Second)
	fmt.Println("Atšaukiama kontekstas...")
	cancel()

	// Duoda laiko gorutinai apdoroti atšaukimą
	time.Sleep(100 * time.Millisecond)
}

Pavyzdys naudojant 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("Apdorojama užklausa User ID:", userID)
	} else {
		fmt.Println("User ID nerastas kontekste")
	}
}

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

Kontekstai yra saugūs kelių gijų ir nekintami, kas yra svarbu konkurenciniam kodui. Jie nėra skirti perduoti neapdorotus funkcijos parametrus, o greičiau metainformacijai, kuri daro įtaką proceso vykdymui.