初学者Go并发(3)

3、worker pool(goroutine池)

在工作中我们通常使用指定启动得goroutine数量-Worker pool模式,来控制goroutine得数量,防止goroutine泄露和暴涨

实例代码如下:

package main

import (
	"fmt"
	"time"
)

func worker(id int, jobs <-chan int, results chan<- int) {
	for j := range jobs {
		fmt.Printf("worker:%d start job:%d", id, j)
		time.Sleep(time.Second)
		fmt.Printf("worker:%d end job:%d", id, j)
		results <- j * 2
	}
}

func main() {
	jobs := make(chan int, 100)
	results := make(chan int, 100)
	//然后开启3个goroutine
	for i := 1; i < 3; i++ {
		go worker(i, jobs, results)
	}
	//5个任务
	for j := 1; j <= 5; j++ {
		jobs <- j
	}
	close(jobs)
	//输出结果
	for a := 1; a < 6; a++ {
		<-results
	}
}

4、Select多路复用

在某些场景下我们需要同时从多个通道接收数据。通道在接收数据时,如果没有数据可以接收将会发生阻塞。你也许会写出如下代码使用遍历的方式来实现:

for{
    // 尝试从ch1接收值
    data, ok := <-ch1
    // 尝试从ch2接收值
    data, ok := <-ch2
    …
}

一般来说这种方式虽然可以实现从多个通道接收值的需求,但是运行性能会差很多。为了应对这种场景,Go内置了select关键字,可以同时响应多个通道的操作。

对于select的使用,其有点类似于switch语句,它有一系列case分支和一个默认的分支。每个case会对应一个通道的通信(接收或发送)过程。select会一直等待,直到某个case的通信操作完成时,就会执行case分支对应的语句。具体格式如下:

select{
    case <-ch1:
        ...
    case data := <-ch2:
        ...
    case ch3<-data:
        ...
    default:
        默认操作
}

看如下例子进行相关的演示

func main(){
    ch:=make(chan int)
    for i:=0;i<100;i++{
        select{
            case x:=<=ch:
            fmt.Println(x)
            case ch<-i:
        }
    }
}

使用select语句能提高代码的可读性。

  • 可处理一个或多个channel的发送/接收操作。
  • 如果多个case同时满足,select会随机选择一个。
  • 对于没有caseselect{}会一直等待,可用于阻塞main函数。

你可能感兴趣的:(golang,java,开发语言)