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 agregarnal 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.Waitpara 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.WaitGrouppuede 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!