1,爲何要控制goroutine的數量? 函數
goroutine當然好,可是數量太多了,每每會帶來不少麻煩,好比耗盡系統資源致使程序崩潰,或者CPU使用率太高致使系統忙不過來。好比:測試
1 for i:=0; i < 10000; i++ { 2 go work() 3 }
2,用什麼方法控制goroutine的數量? spa
要在每一次執行go以前判斷goroutine的數量,若是數量超了,就要阻塞go的執行。第一時間想到的就是使用通道。每次執行的go以前向通道寫入值,直到通道滿的時候就阻塞了,以下:code
1 var ch chan int 2 3 func work() { 4 //do something 5 <-ch 6 } 7 8 func main() { 9 ch = make(chan int, 10) 10 for i:=0; i < 10000; i++ { 11 ch <- 1 12 go work() 13 } 14 }
這樣每次同時運行的goroutine就被限制爲10個了。可是新的問題出現了,由於並非全部的goroutine都執行完了,在main函數退出以後,還有一些goroutine沒有執行完就被強制結束了。這個時候咱們就須要用到sync.WaitGroup。使用WaitGroup等待全部的goroutine退出。以下:blog
1 var wg *sync.WaitGroup 2 3 func work() { 4 defer wg.Done() 5 //do something 6 } 7 8 func main() { 9 wg = &sync.WaitGroup{} 10 for i:=0; i < 10000; i++ { 11 wg.Add(1) 12 go work() 13 } 14 wg.Wait()//等待全部goroutine退出 15 }
3,優雅的使用並控制goroutine的數量 資源
綜上所述,咱們封裝一下,代碼以下:it
1 package gpool 2 3 import ( 4 "sync" 5 ) 6 7 type pool struct { 8 queue chan int 9 wg *sync.WaitGroup 10 } 11 12 func New(size int) *pool { 13 if size <= 0 { 14 size = 1 15 } 16 return &pool{ 17 queue: make(chan int, size), 18 wg: &sync.WaitGroup{}, 19 } 20 } 21 22 func (p *pool) Add(delta int) { 23 for i := 0; i < delta; i++ { 24 p.queue <- 1 25 } 26 for i := 0; i > delta; i-- { 27 <-p.queue 28 } 29 p.wg.Add(delta) 30 } 31 32 func (p *pool) Done() { 33 <-p.queue 34 p.wg.Done() 35 } 36 37 func (p *pool) Wait() { 38 p.wg.Wait() 39 }
來段測試代碼:class
1 package gpool_test 2 3 import ( 4 "runtime" 5 "testing" 6 "time" 7 "gpool" 8 ) 9 10 func Test_Example(t *testing.T) { 11 pool := gpool.New(100) 12 println(runtime.NumGoroutine()) 13 for i := 0; i < 1000; i++ { 14 pool.Add(1) 15 go func() { 16 time.Sleep(time.Second) 17 println(runtime.NumGoroutine()) 18 pool.Done() 19 }() 20 } 21 pool.Wait() 22 println(runtime.NumGoroutine()) 23 }
good job,Over~test