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 mainimport ( "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 ) 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 mainimport ( "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 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 . 程序顺利执行不会出现崩溃情况...