Go Esperando goroutines


Ejemplo

Los programas de Go terminan cuando finaliza la función main , por lo que es una práctica común esperar a que todos los goroutines terminen. Una solución común para esto es usar un objeto sync.WaitGroup .

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup // 1

func routine(i int) {
    defer wg.Done() // 3
    fmt.Printf("routine %v finished\n", i)
}

func main() {
    wg.Add(10) // 2
    for i := 0; i < 10; i++ {
        go routine(i) // *
    }
    wg.Wait() // 4
    fmt.Println("main finished")
}

Ejecutar el ejemplo en el patio de recreo.

Uso de WaitGroup en orden de ejecución:

  1. Declaración de variable global. Hacerlo global es la forma más fácil de hacerlo visible a todas las funciones y métodos.
  2. Aumentar el contador. Esto debe hacerse en la goroutine principal porque no hay garantía de que una goroutine recién iniciada se ejecute antes de las 4 debido a las garantías del modelo de memoria.
  3. Disminuyendo el contador. Esto debe hacerse a la salida de una goroutina. Al utilizar una llamada diferida, nos aseguramos de que se llamará cada vez que la función finalice , sin importar cómo termine.
  4. Esperando que el contador llegue a 0. Esto se debe hacer en la goroutine principal para evitar que el programa salga antes de que todos los goroutines hayan terminado.

* Los parámetros son evaluados antes de comenzar una nueva goroutina . Por lo tanto, es necesario definir sus valores explícitamente antes de wg.Add(10) para que el código de posible pánico no incremente el contador. Añadiendo 10 elementos al WaitGroup, por lo que esperará 10 elementos antes de que wg.Wait devuelva el control a main() goroutine. Aquí, el valor de i se define en el bucle for.