Colas de tareas en Go: guía completa para principiantes

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción a las colas de tareas en Go

\n

Las colas de tareas (task queues) son uno de los patrones clave en el desarrollo de aplicaciones de alta carga. Permiten organizar el procesamiento asíncrono de datos, distribuir la carga y aumentar la tolerancia a fallos del sistema. En el lenguaje Go, gracias a los mecanismos integrados de concurrencia — gorutinas y canales — la implementación de colas se vuelve increíblemente elegante y eficiente.

\n

En este artículo, analizaremos cómo crear colas de tareas en Go desde cero. Aprenderá qué son las gorutinas y los canales, cómo organizar un pool de trabajadores (worker pool) y procesar tareas en paralelo. El material está dirigido a desarrolladores principiantes familiarizados con los conceptos básicos de la sintaxis de Go.

\n\n

Fundamentos: gorutinas y canales

\n

Antes de pasar a las colas, es importante comprender dos conceptos fundamentales de Go:

\n
    \n
  • Gorutina (goroutine) — un hilo de ejecución ligero. Se inicia con la palabra clave go antes de la llamada a una función.
  • \n
  • Canal (channel) — un «canal» tipado para transferir datos entre gorutinas. Permite sincronizar su trabajo.
  • \n
\n

Ejemplo de una gorutina y un canal simples:

\n
package main\n\nimport "fmt"\n\nfunc main() {\n    ch := make(chan string)\n\n    go func() {\n        ch <- "¡Saludo desde la gorutina!"\n    }()\n\n    msg := <-ch\n    fmt.Println(msg)\n}\n
\n

En este ejemplo, creamos un canal ch, iniciamos una gorutina anónima que envía un mensaje a él, y la gorutina principal recibió ese mensaje. Este mecanismo es la base sobre la que se construyen las colas de tareas.

\n\n

Implementación de una cola de tareas simple

\n

La cola de tareas más simple es un canal en el que colocamos tareas, y una o varias gorutinas que las procesan. Veamos un ejemplo básico:

\n
package main\n\nimport (\n    "fmt"\n    "time"\n)\n\nfunc worker(id int, tasks <-chan int) {\n    for task := range tasks {\n        fmt.Printf("Trabajador %d inició tarea %d\\n", id, task)\n        time.Sleep(time.Second) // simulación de trabajo\n        fmt.Printf("Trabajador %d completó tarea %d\\n", id, task)\n    }\n}\n\nfunc main() {\n    tasks := make(chan int, 10) // canal con buffer\n\n    // iniciamos un trabajador\n    go worker(1, tasks)\n\n    // enviamos 5 tareas\n    for i := 1; i <= 5; i++ {\n        tasks <- i\n    }\n\n    close(tasks) // cerramos el canal\n    time.Sleep(2 * time.Second) // damos tiempo para procesar\n}\n
\n

Aquí, worker es una función que lee del canal tasks. El canal tiene buffer (capacidad 10), por lo que podemos enviar varias tareas sin bloqueo. Después de cerrar el canal, el bucle for range finaliza automáticamente.

\n

Tenga en cuenta: usamos <-chan int — un canal de solo lectura. Esta es una buena práctica que indica explícitamente que el trabajador no debe enviar datos a este canal.

\n\n

Canales con buffer y sin buffer

\n

En el ejemplo anterior, usamos un canal con buffer (make(chan int, 10)). La diferencia entre los tipos de canales:

\n
    \n
  • Canal sin buffer — el envío se bloquea hasta que el receptor lea los datos. Ideal para sincronización.
  • \n
  • Canal con buffer — el envío se bloquea solo cuando el buffer está lleno. Permite acumular tareas y reduce las demoras.
  • \n
\n

Para las colas de tareas, generalmente se usan canales con buffer, para que el productor pueda enviar una tarea rápidamente y continuar su trabajo sin esperar a que se ejecute.

\n\n

Pool de trabajadores (Worker Pool) en Go

\n

Un trabajador está bien, pero varios es mejor. Un pool de trabajadores permite procesar tareas en paralelo, utilizando todos los núcleos del procesador. Así es como se implementa:

\n
package main\n\nimport (\n    "fmt"\n    "sync"\n    "time"\n)\n\nfunc worker(id int, tasks <-chan int, wg *sync.WaitGroup) {\n    defer wg.Done()\n    fo                

Blogs

Book Recommendations