Contenido del curso
Fundamentos de Go
Estructuras de Datos y Funciones
- 8

Sentencia switch en Go con ejemplos reales
07:16 min - 9

Arreglos en Go: fijos e inferidos
06:55 min - 10

Creación y uso de slices dinámicos en Go
08:25 min - 11

Mapas en Go: creación, acceso y manipulación de datos clave-valor
09:37 min - 12

Cómo crear y usar funciones personalizadas en Go
07:09 min - 13

Retorno de múltiples valores en Go
07:43 min - 14

Funciones variadic en Go con tres puntos
07:10 min - 15

Funciones recursivas en Go con Fibonacci
06:11 min - 16

Punteros en Go para optimizar rendimiento del sistema
05:19 min - 17

Runas en Go: bytes vs caracteres reales
06:40 min - 18

Declaración y uso de estructuras de datos en Go
09:06 min - 19

Implementación de enumeradores en Go para controlar estados
09:32 min
Manejo de Errores y Concurrencia
Buenas Prácticas en Go
Workers en Go con goroutines y channels
Resumen
Los workers en Go te permiten ejecutar tareas en segundo plano usando goroutines y channels, ideales para procesos que se disparan por eventos o se repiten en intervalos. Si ya conoces goroutine, channel, select y timeout, tienes todo lo necesario para construirlos paso a paso.
¿Qué es un worker y para qué sirve en programación concurrente?
Un worker es un servicio latente que espera a que algo lo desencadene. Piensa en un proceso que limpia tu disco duro cada 24 horas o que reacciona a un evento dentro de una aplicación distribuida.
¿Qué hace un worker en Go? Ejecuta tareas en segundo plano usando goroutines, recibe trabajo por un channel de entrada y entrega resultados por un channel de salida.
La fuerza del patrón está en desacoplar quién pide el trabajo de quién lo ejecuta. Tú lanzas varios workers, ellos toman tareas del canal y devuelven resultados sin bloquear el hilo principal.
¿Cómo se construye la función worker en Go?
La función worker recibe tres argumentos: un identificador entero, un channel de tareas y un channel de resultados. Ambos canales son de tipo int en este ejemplo.
Dentro de la función, un for con range recorre el canal de tareas. Por cada tarea entrante, el worker imprime un mensaje, espera con time.Sleep(time.Second) para simular trabajo, y envía el resultado multiplicado por dos al canal de resultados.
go package main
import ( "fmt" "time" )
func worker(id int, tareas <-chan int, resultados chan<- int) { for j := range tareas { fmt.Println("worker", id, "procesando tarea", j) time.Sleep(time.Second) fmt.Println("worker", id, "tarea iniciada", j) resultados <- j * 2 } }
Una nota práctica: si quieres formatear cadenas con variables, usa Printf con verbos como %d. Si solo concatenas, Println funciona perfecto.
¿Por qué usar channels para tareas y resultados?
Los canales sincronizan la comunicación entre goroutines sin necesidad de mutex manuales. El canal de tareas alimenta a los workers, el de resultados recoge la salida.
¿Cómo orquestar los workers desde main?
En main defines una constante con el número de tareas, creas los dos canales con make y lanzas varios workers en goroutines.
- Declara
const numeroTareas = 5para fijar la cantidad de iteraciones. - Crea los canales con
make(chan int, numeroTareas)para tareas y resultados. - Lanza los workers con un
forque itere por ejemplo dew := 1hasta menor que 3, ejecutandogo worker(w, tareas, resultados).
Un segundo for envía las tareas al canal y luego llama a close(tareas) para indicar que no habrá más trabajo. Sin ese cierre, los workers seguirían esperando para siempre.
¿Qué hace close() en un channel? Cierra el canal e indica a los receptores que ya no llegarán más valores. Es esencial cuando usas
rangesobre un canal.
Finalmente, un tercer for lee del canal de resultados tantas veces como tareas enviaste. Aquí es donde la información llega al hilo principal y puedes mostrarla.
go func main() { const numeroTareas = 5 tareas := make(chan int, numeroTareas) resultados := make(chan int, numeroTareas)
for w := 1; w < 3; w++ { go worker(w, tareas, resultados) } for j := 1; j <= numeroTareas; j++ { tareas <- j } close(tareas) for a := 1; a <= numeroTareas; a++ { <-resultados }
}
¿Por qué los resultados aparecen en desorden?
Al ejecutar go run main.go notarás algo curioso: la tarea 4 puede iniciarse mientras la 3 todavía arranca. Los workers trabajan en paralelo y entregan resultados según terminan, no según entran.
Esto rompe el patrón FIFO (First In, First Out). Cuando trabajas con hilos, la comunicación se vuelve asíncrona y el orden de salida depende de cómo el runtime programa cada goroutine.
¿Por qué los workers no respetan el orden FIFO? Porque varios hilos procesan tareas al mismo tiempo. El que termine primero entrega su resultado primero, sin importar el orden de entrada.
Si tu lógica depende del orden, debes planearlo. Aquí entran herramientas como select y timeout para darle estructura a la concurrencia y evitar que el desorden se convierta en un problema.
Conceptos y habilidades clave del ejercicio
El ejercicio integra varios elementos de Go que vale la pena identificar dentro del código:
- Goroutine: ejecutas
workeren segundo plano congo worker(...), sin bloquearmain. - Channel:
make(chan int, numeroTareas)crea canales con buffer para tareas y resultados. rangesobre canal: recorre tareas hasta que el canal se cierra.close: cierra el canal de tareas y libera alrangedel worker.time.Sleep(time.Second): simula la duración de cada tarea.PrintlnvsPrintf: el primero concatena, el segundo aplica formato con verbos.
Practica modificando el número de workers, agregando un select con timeout o forzando un orden de salida con estructuras adicionales. Cuéntame en los comentarios qué escenario de worker implementarías primero en tu proyecto.