Sobes.tech
Middle

Vertel me over de gebruiksgevallen van de context in Go.

sobes.tech AI

Antwoord van AI

De context in Go wordt gebruikt om de levenscyclus van verzoeken te beheren en de uitvoering van goroutines te controleren. De belangrijkste gebruikssituaties:

  • Annulering: Maakt het mogelijk om de keten van goroutines die met een specifiek verzoek verband houden, te annuleren. Bijvoorbeeld bij het sluiten van de verbinding of door timeout.
  • Timeout: Stelt een uiterste termijn voor de uitvoering in. Als de operatie niet binnen deze termijn wordt voltooid, wordt de context geannuleerd. Dit voorkomt oneindig wachten.
  • Overdracht van verzoekspecifieke gegevens: Maakt het mogelijk om gegevens die betrekking hebben op een specifiek verzoek (zoals gebruikers-ID, trace-identifier) door de call-keten te sturen zonder de handtekeningen te wijzigen.

Voorbeelden van gebruik:

  1. Annulering door signaal:

    package main
    
    import (
    	"context"
    	"fmt"
    	"time"
    )
    
    func worker(ctx context.Context, id int) {
    	for {
    		select {
    		case <-ctx.Done():
    			fmt.Printf("Werker %d onderbroken\n", id)
    			return
    		default:
    			fmt.Printf("Werker %d aan het werk...\n", id)
    			time.Sleep(500 * time.Millisecond)
    		}
    	}
    }
    
    func main() {
    	ctx, cancel := context.WithCancel(context.Background())
    	defer cancel() // Zorgt voor annulering
    
    	go worker(ctx, 1)
    	go worker(ctx, 2)
    
    	time.Sleep(2 * time.Second)
    	cancel() // Annuleert de context
    
    	time.Sleep(500 * time.Millisecond) // Geeft tijd voor goroutines om te eindigen
    }
    
  2. Timeout:

    package main
    
    import (
    	"context"
    	"fmt"
    	"time"
    )
    
    func longOperation(ctx context.Context) error {
    	select {
    	case <-time.After(3 * time.Second): // Simulatie van een lange operatie
    		fmt.Println("Operatie succesvol afgerond")
    		return nil
    	case <-ctx.Done():
    		fmt.Println("Operatie geannuleerd door context:", ctx.Err())
    		return ctx.Err()
    	}
    }
    
    func main() {
    	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    	defer cancel()
    
    	err := longOperation(ctx)
    	if err != nil {
    		fmt.Println("Fout:", err)
    	}
    }
    
  3. Overdracht van gegevens:

    package main
    
    import (
    	"context"
    	"fmt"
    )
    
    type UserKey string
    
    const userIDKey UserKey = "userID"
    
    func processRequest(ctx context.Context) {
    	userID := ctx.Value(userIDKey).(int)
    	fmt.Printf("Verwerking van verzoek voor gebruikers-ID: %d\n", userID)
    	// Verdere verwerking van het verzoek met userID
    }
    
    func main() {
    	ctx := context.WithValue(context.Background(), userIDKey, 123)
    	processRequest(ctx)
    }
    

Het is belangrijk om context.Background() of context.TODO() te gebruiken als de root-context en deze door te geven in de call-keten. Het is niet aan te raden om de context op te slaan in datastructuren als deze niet direct gerelateerd is aan de levenscyclus van die structuur.