如何優雅的控制goroutine的數量

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

相關文章
相關標籤/搜索