Sobes.tech
Middle

Vorbește-mi despre cazurile de utilizare ale contextului în Go.

sobes.tech AI

Răspuns de la AI

Contextul în Go este utilizat pentru gestionarea ciclului de viață al solicitărilor și controlul execuției goroutine-urilor. Principalele cazuri de utilizare:

  • Anulare: Permite anularea lanțului de goroutine-uri asociate unei solicitări specifice. De exemplu, la închiderea conexiunii sau în cazul timeout-ului.
  • Timeout: Stabilește un termen limită pentru finalizarea operației. Dacă operația nu se finalizează în acest interval, contextul este anulat. Acest lucru previne așteptările infinite.
  • Transmiterea datelor specifice solicitării: Permite transmiterea datelor legate de o solicitare concretă (de exemplu, ID-ul utilizatorului, identificatorul de urmărire) prin lanțul de apeluri, fără a modifica semnăturile acestora.

Exemple de utilizare:

  1. Anulare prin semnal:

    package main
    
    import (
    	"context"
    	"fmt"
    	"time"
    )
    
    func worker(ctx context.Context, id int) {
    	for {
    		select {
    		case <-ctx.Done():
    			fmt.Printf("Lucrător %d întrerupt\n", id)
    			return
    		default:
    			fmt.Printf("Lucrător %d lucrând...\n", id)
    			time.Sleep(500 * time.Millisecond)
    		}
    	}
    }
    
    func main() {
    	ctx, cancel := context.WithCancel(context.Background())
    	defer cancel() // Asigură anularea
    
    	go worker(ctx, 1)
    	go worker(ctx, 2)
    
    	time.Sleep(2 * time.Second)
    	cancel() // Anulează contextul
    
    	time.Sleep(500 * time.Millisecond) // Oferă timp goroutine-urilor să se termine
    }
    
  2. Timeout:

    package main
    
    import (
    	"context"
    	"fmt"
    	"time"
    )
    
    func longOperation(ctx context.Context) error {
    	select {
    	case <-time.After(3 * time.Second): // Simulare a unei operații lungi
    		fmt.Println("Operație finalizată cu succes")
    		return nil
    	case <-ctx.Done():
    		fmt.Println("Operație anulată de 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("Eroare:", err)
    	}
    }
    
  3. Transmiterea datelor:

    package main
    
    import (
    	"context"
    	"fmt"
    )
    
    type UserKey string
    
    const userIDKey UserKey = "userID"
    
    func processRequest(ctx context.Context) {
    	userID := ctx.Value(userIDKey).(int)
    	fmt.Printf("Procesarea solicitării pentru ID-ul utilizatorului: %d\n", userID)
    	// Procesarea suplimentară a solicitării cu userID
    }
    
    func main() {
    	ctx := context.WithValue(context.Background(), userIDKey, 123)
    	processRequest(ctx)
    }
    

Este important să folosiți context.Background() sau context.TODO() ca context rădăcină și să îl transmiteți în jos pe lanțul de apeluri. Nu trebuie să stocați contextul în structuri de date dacă nu este direct legat de ciclul de viață al acestei structuri.