Para auxiliar no controle de diversos jobs simultâneos,independentes e ainda com resultados sincronizados podemos lançar mão da WaitGroup.
A WaitGroup aguarda que um determinado número de goroutines sejam finalizadas para prosseguir com a execução. O programa principal faz a chamada para .Add() que recebe como parâmetro o número de goroutines que deve aguardar serem finalizadas.
Exemplo:
waitGroup.Add(3)
No exemplo abaixo demostramos a chamada de três goroutines e a chamada para .Done() ao final de cada uma das goroutines. .Done() por sua vez realiza o decremento do número de goroutines parametrizados em .Add() E antes da finalização da execução do programa principal e após a chamada das goroutines, realizamos a chamada para .Wait() que deve fazer com que toda a execução pare neste ponto, aguardando que o decremento gerado por .Done() chegue a 0.
package main
import "sync"
import "time"
func main() {
println("Inicio")
//Cria um grupo de espera para aguardar o processamento de todos as goroutines
var waitGroup sync.WaitGroup
//Define o número de goroutines que deve ser aguardado.
waitGroup.Add(3)
go func() {
time.Sleep(2 * time.Second)
println(" -> foo")
//Decrementa o contador do WaitGroup.
waitGroup.Done()
}()
go func() {
time.Sleep(3 * time.Second)
println(" -> bar")
waitGroup.Done()
}()
go func() {
time.Sleep(1 * time.Second)
println(" -> qux")
waitGroup.Done()
}()
//Segura a execução até que o contador do WaitGroup chegue a 0.
waitGroup.Wait()
println("Fim")
}
Se você usar em uma função separada lembre de passar a variável que contem o WaitGroup como um ponteiro (*sync.WaitGroup) isso é necessário pois por padrão o copia os parâmetros e nesse caso é necessário passar por referencia para que o decremento feito por .Done() funcione.
Veja o exemplo abaixo:
package main
import (
"math/rand"
"sync"
"time"
)
func rotina(wg *sync.WaitGroup, x int) {
// Espera um tempo aleatório
rt := rand.Int31n(1000)
time.Sleep(time.Duration(rt) * time.Millisecond)
println("rotina", x)
wg.Done()
}
func main() {
println("Inicio")
rand.Seed(time.Now().Unix())
var wg sync.WaitGroup
wg.Add(3)
for i := 1; i < 4; i++ {
go rotina(&wg, i)
}
wg.Wait()
println("Fim")
}