Middle
Fale sobre os casos de uso do contexto em Go.
sobes.tech IA
Resposta da IA
O contexto em Go é utilizado para gerir o ciclo de vida das requisições e controlar a execução das goroutines. Os principais casos de uso:
- Cancelamento: Permite cancelar a cadeia de goroutines relacionada com uma requisição específica. Por exemplo, ao fechar a conexão ou por timeout.
- Timeout: Define um prazo limite para a operação. Se a operação não terminar nesse prazo, o contexto é cancelado. Isto evita esperas infinitas.
- Transferência de dados específicos da requisição: Permite passar dados relacionados com uma requisição concreta (como ID de utilizador, identificador de traçado) através da cadeia de chamadas sem alterar as suas assinaturas.
Exemplos de uso:
-
Cancelamento por sinal:
package main import ( "context" "fmt" "time" ) func worker(ctx context.Context, id int) { for { select { case <-ctx.Done(): fmt.Printf("Trabalhador %d interrompido\n", id) return default: fmt.Printf("Trabalhador %d a trabalhar...\n", id) time.Sleep(500 * time.Millisecond) } } } func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Garantir cancelamento go worker(ctx, 1) go worker(ctx, 2) time.Sleep(2 * time.Second) cancel() // Cancela o contexto time.Sleep(500 * time.Millisecond) // Dá tempo às goroutines para terminar } -
Timeout:
package main import ( "context" "fmt" "time" ) func longOperation(ctx context.Context) error { select { case <-time.After(3 * time.Second): // Simulação de uma operação longa fmt.Println("Operação concluída com sucesso") return nil case <-ctx.Done(): fmt.Println("Operação cancelada pelo contexto:", 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("Erro:", err) } } -
Transferência de dados:
package main import ( "context" "fmt" ) type UserKey string const userIDKey UserKey = "userID" func processRequest(ctx context.Context) { userID := ctx.Value(userIDKey).(int) fmt.Printf("Processando requisição para o ID do usuário: %d\n", userID) // Processamento adicional da requisição usando userID } func main() { ctx := context.WithValue(context.Background(), userIDKey, 123) processRequest(ctx) }
É importante usar context.Background() ou context.TODO() como contexto raiz e passá-lo para baixo na cadeia de chamadas. Não se deve armazenar o contexto em estruturas de dados se ele não estiver diretamente relacionado com o ciclo de vida dessa estrutura.