1. 程式人生 > 實用技巧 >【轉】Go by Example: Worker Pools

【轉】Go by Example: Worker Pools

原文:https://gobyexample.com/worker-pools

Our running program shows the 5 jobs being executed by various workers. The program only takes about 2 seconds despite doing about 5 seconds of total work because there are 3 workers operating concurrently.

package main

import (
    "fmt"
    "time"
)

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

func main() {

    const numJobs = 5
    jobs := make(chan int, numJobs)
    results := make(chan int, numJobs)

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

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

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

  

下面這個版本為什麼會死鎖呢??

 package main
 
 import "fmt"
 import "time"
 
 // Here's the worker, of which we'll run several
 // concurrent instances. These workers will receive
 // work on the `jobs` channel and send the corresponding
 // results on `results`. We'll sleep a second per job to
 // simulate an expensive task.
 func worker(id int, jobs <-chan int, results chan<- int) {
     for j := range jobs {
         fmt.Println("worker", id, "started  job", j)
         time.Sleep(time.Second)
         fmt.Println("worker", id, "finished job", j)
         results <- j * 2
     }
 }
 
 func main() {
 
     // In order to use our pool of workers we need to send
     // them work and collect their results. We make 2
     // channels for this.
     jobs := make(chan int, 100)
     results := make(chan int, 100)
 
     // This starts up 3 workers, initially blocked
     // because there are no jobs yet.
     for w := 1; w <= 3; w++ {
         go worker(w, jobs, results)
     }
 
     // Here we send 5 `jobs` and then `close` that
     // channel to indicate that's all the work we have.
     for j := 1; j <= 5; j++ {
         jobs <- j
     }
     close(jobs)
 
     // Finally we collect all the results of the work.
     //for a := 1; a <= 5; a++ {
     //   fmt.Println( <-results)
     //}
     for v := range results {
       fmt.Println(v)
     }
 }

  

——————————————————————————————————————————————————————————

In this example we’ll look at how to implement aworker poolusing goroutines and channels.

package main
import (
    "fmt"
    "time"
)

Here’s the worker, of which we’ll run several concurrent instances. These workers will receive work on thejobschannel and send the corresponding results onresults. We’ll sleep a second per job to simulate an expensive task.

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

In order to use our pool of workers we need to send them work and collect their results. We make 2 channels for this.

    const numJobs = 5
    jobs := make(chan int, numJobs)
    results := make(chan int, numJobs)

This starts up 3 workers, initially blocked because there are no jobs yet.

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

Here we send 5jobsand thenclosethat channel to indicate that’s all the work we have.

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

Finally we collect all the results of the work. This also ensures that the worker goroutines have finished. An alternative way to wait for multiple goroutines is to use aWaitGroup.

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

Our running program shows the 5 jobs being executed by various workers. The program only takes about 2 seconds despite doing about 5 seconds of total work because there are 3 workers operating concurrently.