Contenido del curso

Estructuras de Datos y Funciones

Select para ordenar goroutines en Go

Resumen

La palabra reservada select en Go es la pieza que ordena la ejecución de tus goroutines cuando trabajas con channels. Si ya dominas concurrencia básica, este operador te permite decidir el orden en que tu aplicación recibe resultados, evitando que una goroutine más rápida arruine la secuencia esperada.

Qué hace select dentro de Go y por qué importa

El operador select hace que tu aplicación espere la ejecución de un channel. Suena burocrático, pero es muy práctico: el channel espera a la goroutine, la goroutine corre en segundo plano, y cuando termina, el valor regresa al hilo principal sin fricción.

La función real de select es seleccionar la interrupción del ciclo de vida de un canal. Es decir, decide qué canal atender y en qué momento, lo que te da control sobre flujos concurrentes que de otra forma serían impredecibles.

¿Para qué sirve select en Go? Sirve para esperar y coordinar la respuesta de uno o varios channels, decidiendo el orden de ejecución de las goroutines asociadas y evitando condiciones de carrera en tu aplicación.

Cómo declarar channels y goroutines antes de usar select

Antes de invocar select necesitas la base: dos paquetes y dos canales listos para recibir datos.

En el ejemplo se importan fmt y time, y dentro de main se declaran dos canales de tipo cadena:

  • canal1 como chan string.
  • canal2 como chan string.
  • Dos goroutines que escriben mensaje uno y mensaje dos en cada canal.

Cada goroutine incluye un time.Sleep para mantener el hilo con vida un par de segundos antes de enviar el mensaje al canal correspondiente. Así simulas una tarea que tarda en resolverse, justo el escenario donde select brilla.

Cómo se escribe el bloque select con un for

El patrón clásico combina un ciclo for con select para escuchar varios canales en secuencia. En el ejercicio se usa:

go for i := 0; i <= 2; i++ { select { case mensaje1 := <-canal1: fmt.Println(mensaje1) case mensaje2 := <-canal2: fmt.Println(mensaje2) } }

select espera a que mensaje1 se ejecute, manda llamar al canal, y luego, en una segunda iteración, atiende mensaje2 con la goroutine del segundo canal. La salida llega ordenada porque select impone la pausa.

Por qué select tarda más y cómo aprovechar esa pausa

Al correr go run main.go notas que el proceso tarda un poco más. No es un error: select va por partes. Primero crea el canal, llama a la goroutine, espera el resultado, lo pasa al hilo principal, y solo entonces atiende la siguiente.

Esa dependencia de pasos es justo lo que necesitas cuando lanzas cinco goroutines y la número tres responde antes que la dos. Sin select, esa diferencia de velocidad rompe la lógica de tu aplicación. Con select, tú defines la secuencia.

¿Cuándo debo usar select en lugar de leer un channel directo? Úsalo cuando manejas dos o más channels simultáneos y necesitas decidir cuál atender primero, o cuando quieres aplicar timeouts para que tu programa no se quede bloqueado esperando.

Cómo encadenar el resultado de un canal con otra goroutine

Un ejercicio adicional muy útil es tomar el resultado de canal1 y enviarlo como entrada a la goroutine de canal2. Así ves cómo la secuencia acumula un conjunto mayor de cadenas en cada paso.

Este patrón te enseña tres cosas a la vez:

  • Cómo encadenar canales en pipeline.
  • Cómo select respeta el orden incluso cuando una tarea es más rápida.
  • Cómo los timeouts con time.Sleep o time.After te dan control sobre tiempos de espera excedidos.

Intenta replicarlo en tu editor, modifica los tiempos de cada Sleep y observa cómo select mantiene el orden aunque las goroutines terminen en momentos distintos. Cuéntame en los comentarios cómo te fue con la práctica y qué errores encontraste al encadenar los canales.