Aguardando execução de múltiplas goroutines

Pense em um cenário onde você abra centenas ou talvez milhares de goroutines, porém que essa quantidade não seja fixa.

Utilizar um channel para controlar a quantidade de goroutines que já finalizaram a execução pode ser muito trabalhoso e em alguns casos até impossível já que, para um channel simples, teriamos que esperar a execução de cada goroutine antes de iniciar a próxima.

Se resolvemos usar um channel com buffer, teremos que especificar sua capacidade durante sua criação, o que também pode nos levar a criar um buffer muito pequeno, onde não conseguimos iniciar todas as goroutines que queremos de uma só vez.

Se você quiser saber mais sobre goroutines e channels antes de continuar, vou deixar aqui a lista com os 3 últimos posts onde abordamos esses assuntos:

Bom, mas se gerir a execução das goroutines com channels pode ser trabalhoso ou em alguns casos até mesmo inviável, como podemos fazer?

Simples, utilizando um package nativo do Go que chama sync. Para ser mais específico, uma struct chamada WaitGroup. Essa struct contém 3 métodos para nos auxiliar nessa tarefa.

  • Add: Incrementa o número de goroutines em execução;
  • Done: Decrementa o número de goroutines em execução;
  • Wait: Aguarda que o número de goroutines em execução chegue a zero.

Para facilitar o entendimento, vamos escrever um pequeno programa para executar um número aleatório de goroutines, entre 0 e 100, onde cada goroutine terá um Sleep entre 0s e 10s.

package main

import (
    "fmt"
    "math/rand"
    "sync"
    "time"
)

func process(num int, wg *sync.WaitGroup) {
    fmt.Printf("iniciando goroutine num %d \n", num)
    time.Sleep(time.Second * time.Duration(rand.Intn(10)))
    fmt.Printf("finalizando goroutine num %d \n", num)

    wg.Done()
}

func main() {
    limit := rand.Intn(100)
    
    var wg sync.WaitGroup
    for i := 0; i <= limit; i++ {
        wg.Add(1)
        go process(i, &wg)
    }

    wg.Wait()

    fmt.Printf("%d goroutines foram finalizadas com sucesso! \n", limit)
}

Nesse exemplo, podemos ver os 3 métodos sendo aplicados.

Antes de iniciar cada uma das goroutines, chamamos o métodos Add para incrementar o número de goroutines em execução.

Passamos o ponteiro da struct para a função process, onde ao final da sua execução chama o método Done da struct WaitGroup, para que seja feito um decremento no número de goroutines.

Fora do nosso for, chamamos o método Wait, para que controle principal do programa fique bloqueado até que todas as goroutines sejam finalizadas.

Deixem suas dúvidas nos comentários.

Até a próxima!


Subscreva

Fique por dentro de tudo o que acontece no mundo Go.

2 comentários sobre “Aguardando execução de múltiplas goroutines

Deixe uma resposta