Go语言控制并发数的两种常用方式

Go语言控制并发数的两种常用方式

Go语言的协程,体积轻量,高效的GPM调度;但是无限的开辟Goroutine数量而不主动去控制,会造成系统资源紧缺遭到panic错误退出;
协程的资源其实是所有用户态共享的资源,所以大批的开辟Goroutine最终引发的灾难不仅是自身,还会关联到其他的程序;
因此在编写业务代码的时候,限制Goroutine是必须重视的问题;

Go语言控制并发数的两种常用方式有:

① 使用有缓冲通道+等待组的方式
② 使用无缓冲通道+等待组任务发送和执行任务分离的方式

① 使用有缓冲通道+等待组的方式

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
31
32
33
34
35
36
37
38
39
// @package    : main
// @file : main.go
// @author : hqd8080
// @contact : hanquanding@163.com
// @time : 2024/4/25
// @description: 使用有缓冲通道+等待组控制Goroutine数量

package main

import (
"fmt"
"math"
"runtime"
"sync"
)

func worker(ch chan bool, wg *sync.WaitGroup, i int) {
defer wg.Done()

fmt.Printf("currentTask:%d, goroutineCount:%d\n", i, runtime.NumGoroutine())
<-ch

return
}

func main() {
var wg sync.WaitGroup

busiTaskCount := math.MaxInt64 // 模拟用户需求的业务并发数量
ch := make(chan bool, 3) // 有缓冲通道,可以达到限制goroutine并发数量的目的,缓存区满阻塞等待

for i := 0; i < busiTaskCount; i++ {
wg.Add(1)
ch <- true
go worker(ch, &wg, i)
}

wg.Wait()
}
1
2
3
4
5
6
7
currentTask:285043, goroutineCount:4
currentTask:285028, goroutineCount:4
currentTask:285045, goroutineCount:4
currentTask:285047, goroutineCount:4
.
.
.

② 使用无缓冲通道+等待组任务发送和执行任务分离的方式实现

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// @package    : main
// @file : main.go
// @author : hqd8080
// @contact : hanquanding@163.com
// @time : 2024/4/25
// @description: 使用无缓冲通道和等待组控制并发数的例子

package main

import (
"fmt"
"math"
"runtime"
"sync"
)

func Worker(ch chan int, wg *sync.WaitGroup) {
for c := range ch {
fmt.Printf("currentTask:%d, goroutineCount:%d\n", c, runtime.NumGoroutine())
wg.Done()
}
}

func sendTask(ch chan int, task int, wg *sync.WaitGroup) {
wg.Add(1)
ch <- task
}

func main() {
var wg sync.WaitGroup

ch := make(chan int) // 无缓冲的整型通道
numGoroutine := 5 // 启动Goroutine的数量

for i := 0; i < numGoroutine; i++ {
go Worker(ch, &wg)
}

busiTaskCount := math.MaxInt64 // 模拟用户需求的业务并发数量

for task := 0; task < busiTaskCount; task++ {
sendTask(ch, task, &wg) // 发送任务
}

wg.Wait()
}
1
2
3
4
5
6
7
currentTask:23853, goroutineCount:6
currentTask:23855, goroutineCount:6
currentTask:23856, goroutineCount:6
currentTask:23851, goroutineCount:6
.

程序顺利执行不会出现崩溃情况...