BufferedChannel&sync.WaitGroup实现并发数控制

利用带缓存的channel和WaitGroup, 可以实现对goroutine的并发数控制. 使用起来非常简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

import (
"fmt"
"sync"
)

func httpGet(url string, limiter chan bool, wg *sync.WaitGroup) {
// 函数执行完毕时 计数器-1
defer wg.Done()
fmt.Println("http get:", url)
// 释放一个坑位
<- limiter
}

func main() {
wg := &sync.WaitGroup{}
// 控制并发数为10
limiter := make(chan bool, 20)

for i := 0; i < 99; i++ {
// 计数器+1
wg.Add(1)
limiter <- true
go httpGet(string(i), limiter, wg)
}
// 等待所以协程执行完毕
wg.Wait() // 当计数器为0时, 不再阻塞
fmt.Println("所有协程已执行完毕")
}

带缓存channel的特性, 当缓存被填满时, for循环中最新一次迭代将阻塞到 limiter <- true 这一行中, 当有其他goroutine执行完毕, 会主动消费limiter中的一个元素, 这样就腾出了一个新的坑位, 之前停留在 limiter <- true 的代码会继续向下执行, 继续循环迭代