1.goroutine池(worker pool)
在平常工作中我们通常会指定启动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\n", id, j)
time.Sleep(time.Second)
fmt.Printf("worker:%d end job:%d\n", id, j)
results <- j * j
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
//开启三个goroutine
for n := 1; n <= 3; n++ {
go worker(n, jobs, results)
}
// 创建五个任务
for i := 0; i < 5; i++ {
jobs <- i
}
//输出结果
for a := 1; a <= 5; a++ {
<-results
}
}
2.select多路复用
在一些情况下需要同时从多个通道接收数据。在通道接收数据时,如果没有数据可能接收将发生阻塞。
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, 1)
for i := 0; i < 10; i++ {
select {
case x := <-ch:
fmt.Println(x)
case ch <- i:
}
}
}
使用select
语句能提高代码的可读性
- 可处理一个或者多个
channel
的发送或者接收操作 - 如果多个
case
同时满足,select
会随机选择一个。 - 对于没有
case
的select{}会一直等待,可用于阻塞main函数。