Go by Example: WaitGroups

Para esperar a que múltiples goroutines terminen, podemos usar un grupo de espera.

package main
import (
    "fmt"
    "sync"
    "time"
)

Esta es la función que ejecutaremos en cada goroutine.

func worker(id int) {
    fmt.Printf("Worker %d starting\n", id)

Dormir para simular una tarea costosa.

    time.Sleep(time.Second)
    fmt.Printf("Worker %d done\n", id)
}
func main() {

Este WaitGroup se utiliza para esperar a que todas las goroutines lanzadas aquí terminen. Nota: si un WaitGroup es explícitamente pasado a funciones, debe hacerse por puntero.

    var wg sync.WaitGroup

Lanzar varias goroutines e incrementar el contador de WaitGroup para cada una.

    for i := 1; i <= 5; i++ {
        wg.Add(1)

Evitar la reutilización del mismo valor de i en cada cierre de goroutine. Consulta las preguntas frecuentes para más detalles.

        i := i

Envolver la llamada al trabajador en un cierre que se asegure de decirle al WaitGroup que este trabajador ha terminado. De esta manera, el trabajador mismo no tiene que ser consciente de los primitivos de concurrencia involucrados en su ejecución.

        go func() {
            defer wg.Done()
            worker(i)
        }()
    }

Bloquear hasta que el contador de WaitGroup vuelva a 0; todos los trabajadores notificaron que han terminado.

    wg.Wait()

Nota que este enfoque no tiene una manera sencilla de propagar errores desde los trabajadores. Para casos de uso más avanzados, considera usar el paquete errgroup.

}
$ go run waitgroups.go
Worker 5 starting
Worker 3 starting
Worker 4 starting
Worker 1 starting
Worker 2 starting
Worker 4 done
Worker 1 done
Worker 2 done
Worker 5 done
Worker 3 done

El orden en que los trabajadores comienzan y terminan probablemente sea diferente en cada invocación.

Siguiente ejemplo: Rate Limiting.