如何優雅的控制goroutine的數量


1,為什么要控制goroutine的數量? 

goroutine固然好,但是數量太多了,往往會帶來很多麻煩,比如耗盡系統資源導致程序崩潰,或者CPU使用率過高導致系統忙不過來。比如:

1 for i:=0; i < 10000; i++ {
2     go work()
3 }

2,用什么方法控制goroutine的數量? 

要在每一次執行go之前判斷goroutine的數量,如果數量超了,就要阻塞go的執行。第一時間想到的就是使用通道。每次執行的go之前向通道寫入值,直到通道滿的時候就阻塞了,如下:

 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退出。如下:

 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的數量 

綜上所述,我們封裝一下,代碼如下:

 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 }

來段測試代碼:

 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~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM