Go con Ejemplos: Pool de trabajadores

En este ejemplo veremos como implementar un pool de trabajadores usando goroutines y canales.

package main
import "fmt"
import "time"

Este es el trabajador del cual correremos varias instancias concurrentes. Estos trabajadores recibirán trabajo desde el canal jobs y enviarán el resultado correspondiente en el canal results. Vamos a hacer una pausa de un segundo por trabajo para simular una tarea pesada.

func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        fmt.Println("trabajador", id,
            "procesando trabajo", j)
        time.Sleep(time.Second)
        results <- j * 2
    }
}
func main() {

Para usar nuestro pool de trabajadores necesitamos enviarles trabajo y recolectar sus resultados. Hacemos dos canales para esto.

    jobs := make(chan int, 100)
    results := make(chan int, 100)

Aquí iniciamos tres trabajadores, inicialmente bloqueados porque no hay trabajos aún.

    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }

Aquí envíamos 9 trabajos por el canal jobs y luego lo cerramos para indicar que ya hay más trabajo por procesar.

    for j := 1; j <= 9; j++ {
        jobs <- j
    }
    close(jobs)

Finalmente recolectamos todos los resultados.

    for a := 1; a <= 9; a++ {
        <-results
    }
}

La salida de nuestro programa muestra que 9 trabajos son ejecutados por varios trabajadores. El programa solo toma cerca de 3 segundos a pesar de que realiza cerca de 9 segundos de trabajo total porque hay 3 trabajadores operando de manera concurrente.

$ time go run examples/worker-pools/worker-pools.go  
trabajador 1 procesando trabajo 1
trabajador 3 procesando trabajo 3
trabajador 2 procesando trabajo 2
trabajador 1 procesando trabajo 4
trabajador 3 procesando trabajo 5
trabajador 2 procesando trabajo 6
trabajador 1 procesando trabajo 7
trabajador 3 procesando trabajo 8
trabajador 2 procesando trabajo 9
real	0m3.380s

Siguiente ejemplo: Limitación de transferencia.