select Statement & Default Cases
select permite que una goroutine espere en múltiples operaciones de canal a la vez.
Busca en todas las páginas de la documentación
select permite que una goroutine espere en múltiples operaciones de canal a la vez.
Agrega default cuando necesites una sonda no bloqueante, un tiempo de espera o un bucle ajustado con otro trabajo.
select se bloquea hasta que al menos un caso pueda proceder: envío, recepción o default.
Si varios casos están listos, Go elige uno de forma pseudoaleatoria.
default se ejecuta inmediatamente cuando ningún caso de canal está listo; nunca lo uses en un bucle de sondeo sin time.Sleep o runtime.Gosched.
Los tiempos de espera combinan select con los plazos de time.After o context.Context.
Tarjeta de receta de referencia rápida - lista para copiar y pegar.
select {
case msg := <-messages:
handle(msg)
case err := <-errors:
log(err)
case <-time.After(5 * time.Second):
return fmt.Errorf("timeout")
default:
// no bloqueante: ningún canal listo en este momento
}Cuándo usar esto:
nil.default en servidores - usar select bloqueante o 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("recibido", v)
close(quit)
case <-time.After(1 * time.Second):
fmt.Println("tiempo de espera agotado")
close(quit)
case <-quit:
fmt.Println("cerrando bucle")
return
}
}
}Lo que esto demuestra:
select.quit canal rompe el bucle después del primer resultado.ch con búfer permite que el remitente complete sin un receptor concurrente en el instante del envío (aún funciona sin búfer con goroutine emparejada).context.WithTimeout sobre time.After crudo en bucles de larga duración (GC del temporizador - ver Gotchas).select evalúa las operaciones de canal como envíos/recepciones independientes, pero espera en el primer caso listo.select (incluidas las expresiones de valor de envío).default evita el bloqueo cuando ningún caso está listo inmediatamente.nil deshabilita esa rama hasta que se reasigna.for { select { ... } } es el bucle de eventos idiomático para goroutines impulsadas por canales.select de un Vistazo| Forma del Caso | Se Bloquea Cuando |
|---|---|
case x := <-ch | No hay valor disponible (a menos que default) |
case ch <- v | Canal lleno (con búfer) o sin receptor (sin búfer) |
case <-ctx.Done() | Contexto no cancelado |
default | Nunca se bloquea |
| Patrón | Notas |
|---|---|
time.After(d) | Simple; asigna un temporizador por iteración en bucles |
context.WithTimeout | Preferido en manejadores HTTP/gRPC |
time.NewTimer + Stop | Reutiliza el temporizador en bucles activos |
// Deshabilita un caso mediante un canal nil
var ch chan int // nil
select {
case v := <-ch: // nunca seleccionado
_ = v
default:
fmt.Println("ch deshabilitado")
}
// Envío no bloqueante
select {
case out <- item:
default:
return ErrQueueFull
}time.After en bucles ajustados - Crea temporizadores que el GC puede tardar en liberar. Solución: time.NewTimer, restablecer con cuidado o context.default - Quema CPU. Solución: bloquear en canales o dormir/ceder entre sondeos.case ch <- expensive() ejecuta expensive() antes de esperar. Solución: calcular antes de select o usar una goroutine interna.break solo sale de select - No del for circundante. Solución: usar etiquetas o return para salir del bucle.| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| Recepción única bloqueante | Un canal de entrada | Múltiples fuentes + tiempo de espera |
| Goroutine separada por fuente | Fan-in simple | Muchas fuentes (combinar con select) |
errgroup + context | Errores de tarea y cancelación | Eventos de canal de grano fino |
Sondeo con default | Comprobaciones de estado raras | Bucles de servidor de alta frecuencia |
No, si varios casos están listos, la selección es pseudoaleatoria.
No dependas del orden textual para la prioridad.
Para intentos de envío/recepción no bloqueantes o sondeos rápidos.
No para hacer sondeo hasta que lleguen los datos.
Casos duplicados en un canal son inútiles; solo uno puede ejecutarse.
Usa canales diferentes o recepciones secuenciales.
Usa return, un caso de canal done, o break con una etiqueta en el bucle for.
Aproximadamente justo entre los casos listos, pero no es un planificador de prioridad.
Diseña prioridad explícita con goroutines separadas si es necesario.
Las operaciones de canal nil nunca proceden, por lo que esos casos se omiten a menos que todos sean nil (interbloqueo).
A menudo indirectamente a través de net/http y context.
Los bucles personalizados multiplexan señales de apagado, colas de trabajo y temporizadores.
default: solo hace un select no bloqueante; útil para intentos de operación, perjudicial en bucles ajustados.
Sí, <-ctx.Done() es idiomático para la cancelación junto con los canales de trabajo.
switch compara valores; select espera la disponibilidad del canal.
Ambos eligen una rama pero resuelven problemas diferentes.
Versiones de Stack: Esta página fue escrita para Go 1.26.x (GC predeterminado Green Tea, go fix modernizers - verificar parche en la compilación), chi (última versión - verificar en la compilación), gin (última versión - verificar en la compilación), echo (última versión - verificar en la compilación), google.golang.org/grpc (última versión - verificar en la compilación), sigs.k8s.io/controller-runtime (última versión - verificar en la compilación), kubebuilder (última versión - verificar en la compilación), tinygo (última versión - verificar objetivos de placa en la compilación), wazero (última versión - verificar en la compilación) y golangci-lint (última versión - verificar conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 18 jul 2026