Golang控制协程的并发量的几种方式
很多情况下,我们需要控制协程的并发量,比如客户端的设备承载限制,客户端业务层面的接口限制等等。我们有以下几种方式来控制。
1、分批请求控制
我们可以设置分批请求,来控制协程当前最多执行多少并发请求。示例:
go
func main() {
total := 50
batchSize := 10
batchChuckReq(total, batchSize)
}
func batchChuckReq(total int, batchSize int) {
for i := 0; i < total; i += batchSize {
end := i + batchSize
if end > total {
end = total
}
var wg sync.WaitGroup
for j := i; j < end; j++ {
wg.Add(1)
go func(j int) {
defer wg.Done()
exec(j)
}(j)
}
wg.Wait() // 等这一批结束
time.Sleep(time.Second * 1)
}
}
func exec(j int) {
fmt.Println(time.Now().Format(time.DateTime), j)
}结果:
2025-10-09 10:11:04 2
2025-10-09 10:11:04 3
2025-10-09 10:11:04 5
2025-10-09 10:11:04 4
2025-10-09 10:11:04 6
2025-10-09 10:11:04 9
2025-10-09 10:11:04 7
2025-10-09 10:11:04 0
2025-10-09 10:11:04 8
2025-10-09 10:11:04 1
2025-10-09 10:11:05 13
2025-10-09 10:11:05 19
2025-10-09 10:11:05 14
2025-10-09 10:11:05 15
2025-10-09 10:11:05 16
2025-10-09 10:11:05 17
2025-10-09 10:11:05 18
2025-10-09 10:11:05 11
2025-10-09 10:11:05 10
2025-10-09 10:11:05 12
2025-10-09 10:11:06 20
2025-10-09 10:11:06 22
2025-10-09 10:11:06 21
2025-10-09 10:11:06 24
2025-10-09 10:11:06 25
2025-10-09 10:11:06 26
2025-10-09 10:11:06 27
2025-10-09 10:11:06 28
2025-10-09 10:11:06 29
2025-10-09 10:11:06 23
2025-10-09 10:11:07 39
2025-10-09 10:11:07 34
2025-10-09 10:11:07 30
2025-10-09 10:11:07 31
2025-10-09 10:11:07 32
2025-10-09 10:11:07 33
2025-10-09 10:11:07 36
2025-10-09 10:11:07 35
2025-10-09 10:11:07 37
2025-10-09 10:11:07 38
2025-10-09 10:11:08 49
2025-10-09 10:11:08 44
2025-10-09 10:11:08 40
2025-10-09 10:11:08 41
2025-10-09 10:11:08 42
2025-10-09 10:11:08 43
2025-10-09 10:11:08 46
2025-10-09 10:11:08 45
2025-10-09 10:11:08 47
2025-10-09 10:11:08 48我们在每个批次执行之后, 延迟一秒再执行下一个批次。可以看到每个批次都协程执行完成了。
2、使用带缓冲的通道
使用带缓冲的通道,将通道的容量设置为每个批次的数量。循环所有要执行的数据,每次写入数据到通道中占位,在协程中释放。
go
func bufferChannelReq(total int, batchSize int) {
ch := make(chan int, batchSize)
var wg sync.WaitGroup
for i := 0; i < total; i++ {
wg.Add(1)
// 占用一个位置
fmt.Println("i=", i)
ch <- i
go func(i int) {
defer wg.Done()
time.Sleep(time.Second)
// 每次调用释放一个位置
fmt.Printf("i=%d, ch=%d\n", i, <-ch)
exec(i)
}(i)
}
wg.Wait()
}3、速率控制
golang.org/x/time/rate 是 Go 官方扩展库(x 系列)中一个非常实用的**限流(Rate Limiting)**包, 它提供了一个高性能、线程安全的令牌桶算法(token bucket)实现。
go
import "golang.org/x/time/rate"
limiter := rate.NewLimiter(10, 20)
for i := 0; i < 100; i++ {
limiter.Wait(context.Background()) // 等待许可
go exec(i)
}