2025-05-15 2025-05-15 约 700 字 预计阅读 2 分钟
一. 不控制goroutine数量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main
import (
"fmt"
"math"
"runtime"
)
func main () {
//模拟用户需求业务的数量
task_cnt := math . MaxInt64
for i := 0 ; i < task_cnt ; i ++ {
go func ( i int ) {
//... do some busi...
fmt . Println ( "go func " , i , " goroutine count = " , runtime . NumGoroutine ())
}( i )
}
}
// panic: too many concurrent operations on a single file or socket (max 1048575)
我们迅速的开辟goroutine(不控制并发的 goroutine 数量 )会在短时间内占据操作系统的资源(CPU、内存、文件描述符等)。
CPU 使用率浮动上涨
Memory 占用不断上涨。
主进程崩溃(被杀掉了)
这些资源实际上是所有用户态程序共享的资源,所以大批的goroutine最终引发的灾难不仅仅是自身,还会关联其他运行的程序。
二. 控制goroutines数量
1 1. 有缓冲channel与sync同步组合方式
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
package main
import (
"fmt"
"math"
"sync"
"runtime"
)
var wg = sync . WaitGroup {}
func busi ( ch chan bool , i int ) {
fmt . Println ( "go func " , i , " goroutine count = " , runtime . NumGoroutine ())
<- ch
wg . Done ()
}
func main () {
//模拟用户需求go业务的数量
task_cnt := math . MaxInt64
ch := make ( chan bool , 3 )
for i := 0 ; i < task_cnt ; i ++ {
wg . Add ( 1 )
ch <- true
go busi ( ch , i )
}
wg . Wait ()
}
2 2. 利用无缓冲channel与任务发送/执行分离方式
生产者消费者模型
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
package main
import (
"fmt"
"math"
"sync"
"runtime"
)
var wg = sync . WaitGroup {}
func busi ( ch chan int ) {
for t := range ch {
fmt . Println ( "go task = " , t , ", goroutine count = " , runtime . NumGoroutine ())
wg . Done ()
}
}
func sendTask ( task int , ch chan int ) {
wg . Add ( 1 )
ch <- task
}
func main () {
ch := make ( chan int ) //无buffer channel
goCnt := 3 //启动goroutine的数量
for i := 0 ; i < goCnt ; i ++ {
//启动go
go busi ( ch )
}
taskCnt := math . MaxInt64 //模拟用户需求业务的数量
for t := 0 ; t < taskCnt ; t ++ {
//发送任务
sendTask ( t , ch )
}
wg . Wait ()
}