Go学习笔记—工作池、等待组、速率限制
1、工作池 Worker Pools
工作池可以让goroutine
安全的共享资源。
通过goroutine
和channel
实现。
func worker(id int,jobs <-chan int,results chan<- int){
for j := range jobs{
fmt.Println("worker",id,"processing job",j)
time.Sleep(time.Second * 2)
results <- j * 2 // 接收通道接收任务后,向results通道发送结果
}
}
func main(){
jobs := make(chan int,100)
results := make(chan int,100)
for w := 1;w <= 3;w++{
go worker(w,jobs,results) // 创建3个工作池
}
for j:=1;j<=9;j++{
jobs <- j // 向工作池接收通道发送任务
}
close(jobs) // 关闭jobs通道
for i:=1;i<=9;i++{
<-results // results通道接收到结果,工作池结束
}
}
定义工作池worker
,参数jobs
为接收通道,results
为发送通道,id
是工作池编号。
工作池的运行时并行的。
2、等待组 WaitGroups
可以使用WaitGroups
等待多个协程goroutine
完成。
使用sync.WaitGroup
定义一个接受者,即可使用等待组的功能。
var wg sync.WaitGroup
wg.Done()
WaitGroup
做函数参数时,要使用指针。
func working(id int,wg *sync.WaitGroup){
defer wg.Done()
fmt.Println("Worker",id,"starting") // 先输出
time.Sleep(time.Second * 6)
fmt.Println("Worker",id,"done") // 6秒后输出
}
func main(){
var wg sync.WaitGroup
for i:=1;i<=5;i++{
wg.Add(1)
go working(i,&wg)
time.Sleep(time.Second) // 输出间隔1秒
}
wg.Wait()
}
//Worker 1 starting
//Worker 2 starting
//Worker 3 starting
//Worker 4 starting
//Worker 5 starting
//Worker 1 done
//Worker 2 done
//Worker 3 done
//Worker 4 done
//Worker 5 done
//主函数在运行之后,每间隔1秒输出一次`Worker 1 starting`,输出5次后,等待1秒,再输出`Worker 1 done`。
利用sleep
来模拟阻塞状态。
根据实例可以看出,当添加了WaitGroup
后,主函数会在所有的goroutine
运行结束后,再结束。
.Done()
:返回所有goroutine
结束运行的状态.Add()
:将参数添加到WaitGroup
计数器.Wait()
:等待goroutine
运行结束,结束主程序
3、速率限制 Rate Limiting
速率限制是一个重要的控制服务资源利用和质量的途径。
通过goroutine
、channel
、ticker
实现。
func main(){
requests := make(chan int,5)
for i := 1;i <= 5;i++{
requests <- i
}
close(requests)
limiter := time.Tick(time.Second)
for req := range requests{
<- limiter
fmt.Println("request",req,time.Now())
}
// 上部分模拟限制速率的传输
burstyLimiter := make(chan time.Time,3)
for i := 0;i<3;i++{
burstyLimiter <- time.Now()
}
go func() {
for t := range time.Tick(time.Second){
burstyLimiter <- t
}
}()
// 模拟整体的速率控制
burstyRequests := make(chan int,5)
for i:=1;i<=5;i++{
burstyRequests <- i
}
close(burstyRequests)
for req := range burstyRequests{
<- burstyLimiter
fmt.Println("request",req,time.Now())
}
// 模拟超过5个介入请求,在通道缓冲影响下的结果
}