Worker Pool (Goroutine pool)

In our work, we usually use the worker Pool mode to control the number of goroutines and prevent goroutine leaks and inflation.

func main(a) {
    jobs := make(chan int.100)
    results := make(chan int.100)
    // Open 3 Goroutines
    for id:=0; id<3; id++ {
        go worker(id, jobs, results)
    }

    // Generate five jobs
    for num:=0; num<5; num++ {
        jobs <- num
    }
    close(jobs)

    // Output the result
    for a := 0; a < 5; a++ {
        <-results
    }
    
    
    // Deadlock, only close(results) available
    //for {
    // x,ok := <- results
    // if ! ok {
    // break
    // }
    // fmt.Println(x)
    / /}
    // Deadlock, only close(results) available
    //for x := range results {
    // fmt.Println(x)
    / /}

}

func worker(id int, jobs <-chan int, results chan<- int)  {
    for j := range jobs {
        time.Sleep(time.Second)
        fmt.Printf("JobID:{%d} Job is:%d \n", id, j)
        results <- j * 2}}Copy the code

The following output is displayed:

JobID:{0} Job is:0
JobID:{2} Job is:2
JobID:{1} Job is:1
JobID:{2} Job is:4
JobID:{0} Job is:3
Copy the code

Select multiplexing

In some scenarios we need to receive data from multiple channels simultaneously. The channel will block if there is no data to receive. You might write the following code to iterate:

for{
    // Try to receive a value from ch1
    data, ok := <-ch1
    // Try to receive a value from CH2Data, ok := <-ch2... }Copy the code

This approach can fulfill the requirement of receiving values from multiple channels, but the performance is much worse. To cope with this scenario, Go has the select keyword built in to respond to multiple channel operations at the same time.

The use of select is similar to the switch statement, with a series of case branches and a default branch. Each case corresponds to a channel’s communication (receive or send) process. Select waits until a case communication completes, and then executes the statement corresponding to the case branch. The specific format is as follows:

select{
    case <-ch1:
        ...
    case data := <-ch2:
        ...
    case ch3<-data:
        ...
    default: Default action}Copy the code

Here is a small example to illustrate the use of select:

func main(a) {
    ch := make(chan int.1)
    for i := 0; i < 10; i++ {
        select {
            case x := <-ch:
                fmt.Println(x)
            case ch <- i:
                fmt.Printf("%d put \n",i)
        }
    }
}
Copy the code

Using select statements improves the readability of your code.

  • Can handle send/receive operations for one or more channels.
  • If multiplecaseSimultaneously satisfied,selectI’m going to pick one at random.
  • With nocasetheselect{}Can be used to block the main function.