🐔WaitGroups Go
En Go, es común ejecutar varias goroutines en paralelo para aprovechar la concurrencia del lenguaje. Sin embargo, coordinar la finalización de estas goroutines puede ser un desafío. Aquí es donde los WaitGroups resultan esenciales.
En esta sección aprenderé cómo esperar de manera eficiente a que un conjunto de goroutines terminen su ejecución antes de que el programa continúe mediante los WG
¿Qué es un WaitGroup?
Un WaitGroup es un contador de goroutines que se utilizan para sincronizar la ejecución en Go. Con un WaitGroup, puedes decirle al programa que espere a que un conjunto de goroutines termine su trabajo antes de continuar con la siguiente tarea. Este mecanismo es crucial para evitar que el programa termine antes de que las goroutines hayan completado su trabajo.
Uso Básico de WaitGroups
La funcionalidad de WaitGroup se maneja principalmente a través de tres métodos:
Add(delta int): Incrementa el contador delWaitGrouppor el valor dedelta.Done(): Decrementa el contador delWaitGroupen uno. Este método es típicamente llamado por las goroutines cuando terminan su trabajo.Wait(): Bloquea la ejecución hasta que el contador delWaitGroupllegue a cero.
Ejemplo Básico: Sincronización de Goroutines
package main
import (
"fmt"
"sync"
)
func tarea(id int, wg *sync.WaitGroup) {
defer wg.Done() // Asegura que Done() se llame cuando la función termine
fmt.Printf("Goroutine %d está trabajando...\\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1) // Incrementa el contador del WaitGroup
go tarea(i, &wg) //&w referencia del objeto, para no trabajar con copias
}
wg.Wait() // Espera hasta que todas las goroutines hayan terminado
fmt.Println("Todas las goroutines han terminado")
}Explicación del Código
Declaración del
WaitGroup: Se declara unWaitGroup(var wg sync.WaitGroup) para controlar la sincronización de las goroutines.Incremento del Contador con
Add: Dentro del bucle,wg.Add(1)incrementa el contador delWaitGroupcada vez que se lanza una nueva goroutine.Decremento del Contador con
Done: Dentro de cada goroutine,defer wg.Done()asegura que el contador se decremente cuando la goroutine termine.Espera a la Finalización con
Wait: Finalmente,wg.Wait()bloquea la ejecución hasta que todas las goroutines hayan llamado aDone()y el contador llegue a cero.Con &wg paso una referencia al objeto Wg: ya que al usar
&wg, estoy pasando la dirección de memoria del objetowg, lo que permite que las goroutines accedan y modifiquen el mismoWaitGroupen lugar de trabajar con una copia.
Salida esperada:
Asegurando el Uso Correcto de WaitGroups
Uso de Add antes de Lanzar la Goroutine
Add antes de Lanzar la GoroutineEs importante siempre llamar a wg.Add(1) antes de lanzar la goroutine. Si Add se llama después, existe la posibilidad de que Wait termine antes de que la goroutine se registre en el WaitGroup, lo que puede llevar a un comportamiento inesperado.
Ejemplo Incorrecto:
Este código puede resultar en un comportamiento inesperado porque wg.Wait() podría ejecutarse antes de que todas las goroutines llamen a Add(1).
Evitar los Panics por Llamadas Incorrectas
Es crucial que el número de llamadas a wg.Done() coincida con el número de llamadas a wg.Add(). De lo contrario, puedes encontrarte con un panic si el contador de WaitGroup se vuelve negativo.
Ejemplo de Error Común:
En este ejemplo, el programa se bloqueará en wg.Wait() porque no se llama a wg.Done() en la goroutine, lo que impide que el contador llegue a cero.
Ejemplo Completo: Sincronización de Múltiples Tareas Concurrentes
Para mostrar el poder de los WaitGroups, consideremos un ejemplo donde diferentes goroutines realizan diferentes tareas de duración variable.
Explicación del Código
Función
tareaRapida: Simula una tarea que toma 1 segundo en completarse.Función
tareaLenta: Simula una tarea que toma 3 segundos en completarse.Sincronización: Ambas tareas se ejecutan en paralelo, y
wg.Wait()asegura que el programa no termine hasta que ambas goroutines completen su trabajo.
Salida esperada:
Conclusión
Los WaitGroups son una herramienta esencial en Go para manejar la sincronización de goroutines de manera eficiente. Aseguran que un conjunto de tareas concurrentes termine antes de proceder con la siguiente parte del programa, lo que es crucial para evitar problemas comunes en programación concurrente como condiciones de carrera o bloqueos inesperados.
Usando Add, Done y Wait correctamente, puedes escribir código concurrente robusto y fácil de mantener.
Last updated