# 如果不控制 Goroutine 的数量会出什么问题？

`demo1.go`

``````package main

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

func main() {
//模拟用户需求业务的数量

for i := 0; i < task_cnt; i++ {
go func(i int) {
//... do some busi...

fmt.Println("go func ", i, " goroutine count = ", runtime.NumGoroutine())
}(i)
}
}

``````signal: killed

• CPU 使用率浮动上涨
• Memory 占用不断上涨
• 主进程崩溃（被杀掉了）

# 控制 goroutine 的几种方法

## 方法一：用有 buffer 的 channel 来限制

``````package main

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

// 模拟执行业务的 goroutine
func doBusiness(ch chan bool, i int) {
fmt.Println("go func:", i, "goroutine count:", runtime.NumGoroutine())
<-ch
}

func main() {
max_cnt := math.MaxInt64
// max_cnt := 10
fmt.Println(max_cnt)

ch := make(chan bool, 3)

for i := 0; i < max_cnt; i++ {
ch <- true
}
}

``````...
go func  352283  goroutine count =  4
go func  352284  goroutine count =  4
go func  352285  goroutine count =  4
go func  352286  goroutine count =  4
go func  352287  goroutine count =  4
go func  352288  goroutine count =  4
go func  352289  goroutine count =  4
go func  352290  goroutine count =  4
go func  352291  goroutine count =  4
go func  352292  goroutine count =  4
go func  352293  goroutine count =  4
go func  352294  goroutine count =  4
go func  352295  goroutine count =  4
go func  352296  goroutine count =  4
go func  352297  goroutine count =  4
go func  352298  goroutine count =  4
go func  352299  goroutine count =  4
go func  352300  goroutine count =  4
go func  352301  goroutine count =  4
go func  352302  goroutine count =  4
...

`````` for i := 0; i < go_cnt; i++ {
ch <- true
go busi(ch, i)
}

`for` 循环里 `ch<- true` 的速度，因为这个速度决定了 go 的创建速度，而 go 的结束速度取决于  `doBusiness()` 函数的执行速度。这样实际上，我们就能够保证了，同一时间内运行的 goroutine 的数量与 buffer 的数量一致，从而达到了限定效果。

``````package main

import (
"fmt"
// "math"
"runtime"
)

func doBusiness(ch chan bool, i int) {
fmt.Println("go func:", i, "goroutine count:", runtime.NumGoroutine())
<-ch
}

func main() {
// max_cnt := math.MaxInt64
max_cnt := 10

ch := make(chan bool, 3)

for i := 0; i < max_cnt; i++ {
ch <- true
}
}

``````go func  2  goroutine count =  4
go func  3  goroutine count =  4
go func  4  goroutine count =  4
go func  5  goroutine count =  4
go func  6  goroutine count =  4
go func  1  goroutine count =  4
go func  8  goroutine count =  4

## 方法二：使用 sync 同步机制

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

var wg = sync.WaitGroup{}

fmt.Println("go func ", i, " goroutine count = ", runtime.NumGoroutine())
wg.Done()
}

func main() {
//模拟用户需求业务的数量

for i := 0; i < task_cnt; i++ {
}

wg.Wait()
}

## 方法三：channel 与 sync 同步组合方式实现控制 goroutine

``````package main

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

var wg = sync.WaitGroup{}

func doBusiness(ch chan bool, i int) {

fmt.Println("go func ", i, " goroutine count = ", runtime.NumGoroutine())

<-ch

wg.Done()
}

func main() {
//模拟用户需求go业务的数量

ch := make(chan bool, 3)

for i := 0; i < task_cnt; i++ {
ch <- true
}

wg.Wait()
}

``````//...
go func  228856  goroutine count =  4
go func  228857  goroutine count =  4
go func  228858  goroutine count =  4
go func  228859  goroutine count =  4
go func  228860  goroutine count =  4
go func  228861  goroutine count =  4
go func  228862  goroutine count =  4
go func  228863  goroutine count =  4
go func  228864  goroutine count =  4
go func  228865  goroutine count =  4
go func  228866  goroutine count =  4
go func  228867  goroutine count =  4
//...

## 方法四：利用无缓冲 channel 与任务发送/执行分离方式

``````package main

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

var wg = sync.WaitGroup{}

for t := range ch {
fmt.Println("go task = ", t, ", goroutine count = ", runtime.NumGoroutine())
wg.Done()
}
}

}

func main() {

ch := make(chan int)   //无buffer channel

goCnt := 3              //启动goroutine的数量
for i := 0; i < goCnt; i++ {
//启动go
}

for t := 0; t < taskCnt; t++ {
//发送任务