WaitGroup
“Sincronizando Goroutines con Sync.WaitGroup en Go”
🚀 Introducción
Escribir software concurrente puede ser un desafío, pero el lenguaje de programación Go hace que sea más fácil. Consideremos el caso en el que necesitamos realizar varias tareas simultáneamente y tenemos que esperar a que todas ellas terminen antes de continuar. Aquí es donde entra en juego sync.WaitGroup
. En este artículo, exploraremos cómo usar sync.WaitGroup
en Go para sincronizar la ejecución de goroutines. Aprenderás cómo se utiliza sync.WaitGroup
, cuándo utilizarlo y cómo evitar errores comunes.
📘 Fundamentos teóricos
sync.WaitGroup
es una estructura simple de Go que espera a que una colección de goroutines finalice su ejecución antes de permitir que el programa continue. Es un mecanismo de conteo que incrementa su contador cuando agregas una goroutine y lo disminuye cuando una goroutine completa su ejecución. Cuando el contador llega a cero, desbloquea todas las goroutines en espera.
Se usa en situaciones donde necesitas ejecutar varias tareas de manera concurrente y necesitas que todas ellas terminen antes de proceder. Este es un patrón común en muchos programas - por ejemplo, si estás realizando múltiples operaciones independientes que pueden hacerse en paralelo, pero tu programa necesita esperar a que todas terminen antes de continuar.
var wg sync.WaitGroup
El WaitGroup
debe ser una variable compartida a la que las goroutines tienen acceso, es decir, deben compartir el mismo WaitGroup
. Puedes crearlo como una variable global o pasarlo a tus goroutines como argumento.
👨💻 Implementación Paso a Paso
El uso más común de sync.WaitGroup
tiene tres etapas:
- Agregar al contador
Usa
wg.Add(<n>)
para agregarn
al contador:
wg.Add(1)
- Lanzar la goroutine
Lanza tu funcion en una goroutine. En un defer, escribe
wg.Done()
para indicar que la goroutine ha terminado su ejecución:
go func() {
defer wg.Done()
// Código de tu goroutine
}()
- Esperar
Finalmente, después de lanzar todas tus goroutines, usa
wg.Wait
para bloquear el programa hasta que todas las goroutines hayan completado su ejecución:
wg.Wait()
Aquí hay un ejemplo completo que ejecuta 3 goroutines:
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d starting\n", id)
// Simulamos un trabajo costoso con un Sleep
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
// Añade una goroutine al contador
wg.Add(1)
go worker(i, &wg)
}
// Espera a que todas las goroutines finalicen
wg.Wait()
}
Al ejecutar este programa, verás que espera a que todas las goroutines terminen antes de que el programa finalice.
🏢 Casos de Uso Reales
sync.WaitGroup
es útil en muchas situaciones. Aquí tienes dos ejemplos:
- Web scraping: Podrías querer extraer datos de varios sitios web de manera concurrente y esperar a que todos terminen antes de procesar los datos.
- APIs de fetch: Si tu aplicación depende de varias APIs,
sync.WaitGroup
puede ser útil para hacer las llamadas a la API en paralelo y esperar que todas respondan antes de continuar.
🚀 Patrones Avanzados
También puedes usar sync.WaitGroup
junto con select
y channels
para crear patrones más complejos, por ejemplo, para implementar timeouts o para cancelar goroutines. Ten en cuenta que WaitGroup
no tiene una cancelación incorporada, por lo que si necesitas cancelar goroutines, tendrás que usar context
o canales.
👋 Conclusión y Recursos
En este artículo, has aprendido cómo usar sync.WaitGroup
para sincronizar la ejecución de goroutines en Go. Aunque WaitGroup
es una herramienta simple, puede ser poderosa cuando se usa correctamente. Como siempre, recuerda probar tu código y manejar los errores. Aquí está la documentación oficial de WaitGroup para más detalles. También podrías querer explorar otros mecanismos de synchronización proporcionados by Go, como Mutex
y Channel
.
¡Feliz codificación!