Go-控制协程数量
背景
GMP的无限创建Goroutine基于共享用户态资源,过多的协程会导致CPU利用率浮动上涨、内存占用上涨、主进程崩溃
如何控制Goroutine数量
基于buffer的channel
原理:通过buffer的缓冲区的大小和阻塞等待来控制最大的数量
package main
import ( "fmt" "runtime" "time" )
func doGoroutine(i int, ch chan bool) { fmt.Println("go func", i, "goroutine count", runtime.NumGoroutine()) <-ch } func main() { task_cnt := 10 ch := make(chan bool, 3) for i := 0; i < task_cnt; i++ { ch <- true go doGoroutine(i, ch) } time.Sleep(100 * time.Second) }
|
结合sync同步机制
如果单独使用sync机制,耗费速度小于Go生产速度,GO还是会出现数量溢出
package main
import ( "fmt" "runtime" "sync" )
var wg sync.WaitGroup
func doGoroutine(i int, ch chan bool) { fmt.Println("go func", i, "goroutine count", runtime.NumGoroutine()) wg.Done() <-ch } func main() { task_cnt := 10 ch := make(chan bool, 3) for i := 0; i < task_cnt; i++ { wg.Add(1) ch <- true go doGoroutine(i, ch) } wg.Wait() }
|
基于无buffer 的channel分离机制
package main
import ( "fmt" "math" "runtime" "sync" )
func doGoroutine(ch chan int) { for task := range ch { fmt.Println("go task", task, "goroutine count", runtime.NumGoroutine()) wg.Done() }
} func sendTask(task int, ch chan int) { wg.Add(1) ch <- task }
var wg sync.WaitGroup
func main() { ch := make(chan int) goCnt := 3 for i := 0; i < goCnt; i++ { go doGoroutine(ch) } taskCnt := math.MaxInt for i := 0; i < taskCnt; i++ { sendTask(i, ch) } wg.Wait() }
|