select Statement & Default Cases
select permite que uma goroutine espere em múltiplas operações de canal ao mesmo tempo.
Busque em todas as páginas da documentação
select permite que uma goroutine espere em múltiplas operações de canal ao mesmo tempo.
Adicione default quando precisar de uma sondagem não bloqueante, timeout ou loop apertado com outro trabalho.
select bloqueia até que pelo menos um caso possa prosseguir: send, receive, ou default.
Se vários casos estiverem prontos, Go escolhe um pseudo-aleatoriamente.
default é executado imediatamente quando nenhum caso de canal está pronto - nunca o use em um loop de spin sem time.Sleep ou runtime.Gosched.
Timeouts combinam select com time.After ou deadlines de context.Context.
Cartão de receita de referência rápida - pronto para copiar e colar.
select {
case msg := <-messages:
handle(msg)
case err := <-errors:
log(err)
case <-time.After(5 * time.Second):
return fmt.Errorf("timeout")
default:
// não bloqueante: nenhum canal pronto no momento
}Quando usar isso:
nil.default em servidores - use select bloqueante ou goroutines separadas.package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan string, 1)
quit := make(chan struct{})
go func() {
time.Sleep(200 * time.Millisecond)
ch <- "result"
}()
for {
select {
case v := <-ch:
fmt.Println("recebido", v)
close(quit)
case <-time.After(1 * time.Second):
fmt.Println("timeout")
close(quit)
case <-quit:
fmt.Println("encerrando loop")
return
}
}
}O que isso demonstra:
select.quit canal quebra o loop após o primeiro resultado.ch com buffer permite que o remetente conclua sem um receptor concorrente no momento do envio (ainda funciona sem buffer com goroutine pareada).context.WithTimeout em vez de time.After bruto em loops de longa duração (GC de timer - veja Gotchas).select avalia operações de canal como sends/receives independentes, mas espera pelo primeiro caso pronto.select (incluindo expressões de valor de send).default contorna o bloqueio quando nenhum caso está imediatamente pronto.nil desabilita esse branch até que seja reatribuído.for { select { ... } } é o loop de eventos idiomático para goroutines orientadas a canal.| Forma do Caso | Bloqueia quando |
|---|---|
case x := <-ch | Nenhum valor disponível (a menos que default) |
case ch <- v | Canal cheio (bufferizado) ou nenhum receptor (não bufferizado) |
case <-ctx.Done() | Contexto não cancelado |
default | Nunca bloqueia |
| Padrão | Notas |
|---|---|
time.After(d) | Simples; aloca timer por iteração em loops |
context.WithTimeout | Preferido em manipuladores HTTP/gRPC |
time.NewTimer + Stop | Reutiliza timer em loops quentes |
// Desabilita um caso por canal nil
var ch chan int // nil
select {
case v := <-ch: // nunca selecionado
_ = v
default:
fmt.Println("ch desabilitado")
}
// Send não bloqueante
select {
case out <- item:
default:
return ErrQueueFull
}time.After em loops apertados - Cria timers que o GC pode demorar para liberar. Correção: time.NewTimer, reinicie cuidadosamente, ou context.default - Consome CPU. Correção: bloqueie em canais ou durma/ceda entre as sondagens.case ch <- expensive() executa expensive() antes de esperar. Correção: calcule antes do select ou use uma goroutine interna.break sai apenas do select - Não do for circundante. Correção: use rótulos ou return para sair do loop.| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Receive bloqueante único | Um canal de entrada | Múltiplas fontes + timeout |
| Goroutine separada por fonte | Fan-in simples | Muitas fontes (combine com select) |
errgroup + context | Erros de tarefa e cancelamento | Eventos de canal de granularidade fina |
Sondar com default | Verificações de status raras | Loops de servidor de alta frequência |
Não - se múltiplos casos estiverem prontos, a seleção é pseudo-aleatória.
Não dependa da ordem textual para prioridade.
Para tentativas de send/receive não bloqueantes ou sondagens rápidas.
Não para esperar até que os dados cheguem.
Casos duplicados no mesmo canal são inúteis - apenas um pode ser executado.
Use canais diferentes ou receives sequenciais.
Use return, um caso de canal done, ou break com um rótulo no loop for.
Aproximadamente justo entre os casos prontos, mas não é um escalonador de prioridade.
Projete prioridade explícita com goroutines separadas, se necessário.
Operações em canais nil nunca progridem, então esses casos são ignorados, a menos que todos sejam nil (deadlock).
Frequentemente indiretamente via net/http e context.
Loops personalizados multiplexam sinais de desligamento, filas de trabalho e tickers.
default: sozinho cria um select não bloqueante - útil para try-ops, prejudicial em loops apertados.
Sim - <-ctx.Done() é idiomático para cancelamento ao lado de canais de trabalho.
switch compara valores; select espera pela prontidão do canal.
Ambos escolhem um branch, mas resolvem problemas diferentes.
Versões de Stack: Esta página foi escrita para Go 1.26.x (GC padrão Green Tea, go fix modernizers - verifique o patch na compilação), chi (última - verifique na compilação), gin (última - verifique na compilação), echo (última - verifique na compilação), google.golang.org/grpc (última - verifique na compilação), sigs.k8s.io/controller-runtime (última - verifique na compilação), kubebuilder (última - verifique na compilação), tinygo (última - verifique os alvos de placa na compilação), wazero (última - verifique na compilação) e golangci-lint (última - verifique o conjunto de linters na compilação).
Revisado por Chris St. John·Última atualização: 18 de jul. de 2026