Middle
Parlami dei casi d'uso del contesto in Go.
sobes.tech AI
Risposta dell'AI
Il contesto in Go viene utilizzato per gestire il ciclo di vita delle richieste e controllare l'esecuzione delle goroutine. I principali casi d'uso:
- Annullamento: Permette di annullare la catena di goroutine associata a una richiesta specifica. Ad esempio, alla chiusura della connessione o in caso di timeout.
- Timeout: Imposta un termine massimo per l'esecuzione. Se l'operazione non termina entro questo limite, il contesto viene annullato. Questo previene attese infinite.
- Trasmissione di dati specifici della richiesta: Permette di trasmettere dati relativi a una richiesta specifica (ad esempio, ID utente, identificatore di tracciamento) attraverso la catena di chiamate senza modificarne le firme.
Esempi di utilizzo:
-
Annullamento tramite segnale:
package main import ( "context" "fmt" "time" ) func worker(ctx context.Context, id int) { for { select { case <-ctx.Done(): fmt.Printf("Lavoratore %d interrotto\n", id) return default: fmt.Printf("Lavoratore %d in funzione...\n", id) time.Sleep(500 * time.Millisecond) } } } func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Garantisce l'annullamento go worker(ctx, 1) go worker(ctx, 2) time.Sleep(2 * time.Second) cancel() // Annulla il contesto time.Sleep(500 * time.Millisecond) // Permette alle goroutine di terminare } -
Timeout:
package main import ( "context" "fmt" "time" ) func longOperation(ctx context.Context) error { select { case <-time.After(3 * time.Second): // Simulazione di un'operazione lunga fmt.Println("Operazione completata con successo") return nil case <-ctx.Done(): fmt.Println("Operazione annullata dal contesto:", 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("Errore:", err) } } -
Trasmissione di dati:
package main import ( "context" "fmt" ) type UserKey string const userIDKey UserKey = "userID" func processRequest(ctx context.Context) { userID := ctx.Value(userIDKey).(int) fmt.Printf("Elaborazione richiesta per l'ID utente: %d\n", userID) // Ulteriore elaborazione della richiesta con userID } func main() { ctx := context.WithValue(context.Background(), userIDKey, 123) processRequest(ctx) }
È importante usare context.Background() o context.TODO() come contesto radice e passarli lungo la catena di chiamate. Non si dovrebbe memorizzare il contesto in strutture dati se non è direttamente collegato al ciclo di vita di quella struttura.