Go by Example - IT: Worker Pool

In questo esempio vedremo come implementare un worker pool usando le goroutine e i channel.

package main
import "fmt"
import "time"

Questo è il worker, sul quale eseguiremo i nostri task concorrenti. Questi worker riceveranno i task da eseguire sul channel jobs ed invieranno i risultati sul channel results. In questo esempio abbiamo inserito una Sleep da un secondo per simulare un task oneroso.

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

Per poter utilizzare il pool di worker dobbiamo poter inviare i task e poter ricevere i risultati, creiamo dunque due channel per questo

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

Questo farà partire 3 worker, che saranno inizialmente bloccati in quanto non hanno task da eseguire.

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

Inviamo 9 task da eseguire sul channel job ed invochiamo la close su quel canale, in modo da indicare che non ci sono altri task da eseguire.

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

Infine recuperiamo i risultati delle computazioni sul channel results

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

Il nostro programma in esecuzione mostra i 9 task che vengono eseguiti dai vari worker. Il programma termina in circa 3 secondi, anche se il totale dei task avrebbe richiesto 9 secondi. Questo perchè ci sono 3 worker che vengono eseguiti in parallelo

$ time go run worker-pools.go 
worker 1 sta eseguendo task job 1
worker 2 sta eseguendo task job 2
worker 3 sta eseguendo task job 3
worker 1 sta eseguendo task job 4
worker 2 sta eseguendo task job 5
worker 3 sta eseguendo task job 6
worker 1 sta eseguendo task job 7
worker 2 sta eseguendo task job 8
worker 3 sta eseguendo task job 9
real	0m3.149s

Prossimo esempio: Rate Limiting.