Sentencia Select
Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy. Lección 62 de 107.
La instrucción select permite que una goroutine espere simultáneamente varias operaciones de canal. Es como una instrucción switch, pero cada caso implica un envío o una recepción por un canal. Cuando varios canales están listos, select elige uno al azar.
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() { ch1 <- "from channel 1" }()
go func() { ch2 <- "from channel 2" }()
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
}
}Sin select, recibir de ch1 se bloquearía hasta que llegaran datos, lo que podría hacer que se perdieran datos en ch2. Con select, se gestiona el canal que recibe datos primero.
El caso default hace que select no sea bloqueante. Se ejecuta inmediatamente si ningún canal está listo:
select {
case msg := <-messages:
fmt.Println("Received:", msg)
default:
fmt.Println("No message available")
}Un patrón común combina select con tiempos de espera mediante time.After, que devuelve un canal que recibe un valor después de la duración especificada:
select {
case result := <-ch:
fmt.Println("Got result:", result)
case <-time.After(2 * time.Second):
fmt.Println("Timeout!")
}Esto evita que tu programa espere para siempre cuando una operación de canal podría no completarse nunca.
Desafío
FácilConstruyamos un monitor de servicios que use la instrucción select para gestionar múltiples fuentes de datos concurrentes. Tu monitor escuchará simultáneamente diferentes canales de servicio y responderá adecuadamente cuando lleguen datos o cuando no haya actualizaciones disponibles.
Organizarás tu código en dos archivos:
monitor.go: Define la lógica de monitorización de servicios con gestión de canales basada en select.Crea una estructura
ServiceUpdatecon camposName(string) yStatus(string).Implementa una función
Monitorque reciba tres canales:primary chan ServiceUpdate,backup chan ServiceUpdateydone chan bool. Esta función debe usarselectpara escuchar simultáneamente en los tres canales:- Al recibir de
primary: devuelve la cadena formateadaPrimary: [Name] is [Status] - Al recibir de
backup: devuelve la cadena formateadaBackup: [Name] is [Status] - Al recibir de
done: devuelveMonitoring stopped
Implementa una función
CheckStatusque reciba un únicoupdates chan ServiceUpdatey useselectcon un casodefaultpara realizar una comprobación no bloqueante:- Si hay una actualización disponible: devuelve
Update available: [Name] - Si no hay ninguna actualización disponible (caso predeterminado): devuelve
No updates pending
- Al recibir de
main.go: Configura los canales y muestra el comportamiento de select bloqueante y no bloqueante.Lee un modo de la entrada que determine qué escenario ejecutar:
primary,backup,stopocheck.Para los modos
primary,backupystop: lee también un nombre y un estado de servicio. Crea los tres canales, inicia una goroutine que envíe datos al canal correspondiente según el modo, después llama aMonitore imprime su resultado.Para el modo
check: lee un nombre y un estado de servicio, además de una marca (sendonosend) que indique si se deben enviar datos antes de realizar la comprobación. Crea un canal con búfer y capacidad 1. Si la marca essend, envía una actualización al canal antes de llamar aCheckStatus. Imprime el resultado deCheckStatus.
Se proporcionarán las siguientes entradas:
- Línea 1: Modo (
primary,backup,stopocheck) - Línea 2: Nombre del servicio
- Línea 3: Estado del servicio
- Línea 4 (solo para el modo
check):sendonosend
Por ejemplo, dada la siguiente entrada:
primary
Database
healthyTu salida debería ser:
Primary: Database is healthyY dada la siguiente entrada:
check
Cache
active
nosendTu salida debería ser:
No updates pendingPruébalo tú mismo
package main
import (
"fmt"
)
func main() {
var mode string
fmt.Scanln(&mode)
var serviceName string
fmt.Scanln(&serviceName)
var serviceStatus string
fmt.Scanln(&serviceStatus)
// TODO: Maneja diferentes modos: "primary", "backup", "stop", "check"
// Para los modos "primary", "backup", "stop":
// - Crea tres canales: primary, backup, done
// - Lanza una goroutine que envía datos al canal apropiado
// - Llama a Monitor e imprime el resultado
// Para el modo "check":
// - Lee el flag adicional ("send" o "nosend")
// - Crea un canal con buffer de capacidad 1
// - Si el flag es "send", envía una actualización al canal
// - Llama a CheckStatus e imprime el resultado
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de POO en Go
Archivos externosEspacio de trabajo y módulos de GoPaquetes e importacionesNombres exportados vs. no exportadosIntroducción a la POO en GoStructs como clasesDefinición de métodos en structsReceptores de puntero vs. de valorInicialización de structsFunciones constructorasResumen - Calculadora simple4Interfaces
Introducción a las interfacesImplementación implícitaLa interfaz como contratoInterfaz vacía (any)Type AssertionType SwitchComposición de interfacesInterfaces Stringer y ErrorResumen: Calculadora de figuras7Encapsulamiento
Campos exportados vs. no exportadosEncapsulamiento a nivel de paqueteMétodos Getter y SetterOcultamiento de información en GoResumen - Registros de estudiantes10Genéricos (Go 1.18+)
Introducción a los GenéricosParámetros de tipoRestricciones de tipoStructs genéricosSolución alternativa para métodos genéricosResumen - Colección genérica13Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón Abstract FactoryPatrón ObserverPatrón Strategy2Inmersión profunda en Tipos y Structs
Tipos básicos y compuestosDefiniciones de tipos personalizadosEtiquetas de StructsStructs anónimosStructs anidadosValores cero y por defectoRepaso - Libreta de contactos5Composición sobre herencia
Por qué Go no tiene herenciaConceptos básicos de incrustación de structsPromoción de métodosIncrustación de múltiples structsIncrustación vs AgregaciónShadowing de métodos incrustadosResumen - Jerarquía de empleados8Manejo de Errores y OOP
La interfaz errorTipos de errores personalizadosEnvoltura de errores (fmt.Errorf)Errores centinelaerrors.Is() y errors.As()Panic, Defer y RecoverResumen - Analizador de archivos3Punteros y Memoria
Fundamentos de punteros en GoPunteros a StructsPaso por valor vs referenciaLa función new()Garbage Collection en GoResumen - Constructor de Linked List6Polimorfismo en Go
Polimorfismo mediante interfacesDuck Typing en GoReglas de satisfacción de interfacesColecciones polimórficasInyección de dependenciasResumen - Procesador de pagos9Concurrencia y POO
Fundamentos de GoroutinesChannels y comunicaciónChannels con buffer vs. sin bufferSentencia Selectsync.Mutex y sync.RWMutexsync.WaitGroupDiseño de estructuras Thread-SafeResumen - Worker PoolPractica por tu cuenta: Compilador de Go online