对 golang 中的 goroutine 数量进行控制
简介
- 在
golang
中开启一个 goroutine 是一件很便捷的事情
- 但是如果不对其进行控制,则可能造成 goroutine 泛滥成灾
- 本文就对如何控制 goroutine 数量进行一个尝试
- 主要思路是通过 chan 实现,取一个协程就向 chan 中写入,如果协程被取完则会阻塞,用完一个协程就从通道中拿出一个即可
代码
- for 循环中不停的开启新的协程
- 每隔一秒钟打印当前的协程数
没有协程池
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
| package main
import ( "fmt" "runtime" "time" )
func main() { withoutGoroutinePool() }
func withoutGoroutinePool() { ticker := time.NewTicker(time.Second) for { select { case <-ticker.C: fmt.Println(time.Now().String(), runtime.NumGoroutine()) break default: go sleep() } }
}
func sleep() { time.Sleep(100 * time.Millisecond) }
|
- 输出结果如下所示,可以看出 Goroutine 的数量超多,在几十万之多,可能会瞬间打满 cpu
1 2 3 4 5 6 7 8 9 10 11
| ➜ aaa git:(dev) ✗ go run main.go 2020-02-10 22:21:07.708449 +0800 CST m=+1.075829140 258734 2020-02-10 22:21:08.63268 +0800 CST m=+2.000078344 340130 2020-02-10 22:21:09.63266 +0800 CST m=+3.000079432 394476 2020-02-10 22:21:10.632632 +0800 CST m=+4.000071378 418946 2020-02-10 22:21:11.632619 +0800 CST m=+5.000079498 406332 2020-02-10 22:21:12.632586 +0800 CST m=+6.000066992 406157 2020-02-10 22:21:13.632612 +0800 CST m=+7.000113855 366507 2020-02-10 22:21:14.632658 +0800 CST m=+8.000180030 369627 2020-02-10 22:21:15.632572 +0800 CST m=+9.000114252 397764 ^Csignal: interrupt
|
有协程池
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 47 48 49 50 51
| package main
import ( "fmt" "runtime" "time" )
type goroutinePool struct { c chan interface{} }
var pool *goroutinePool
func newGoroutinePool(size int) *goroutinePool { return &goroutinePool{c: make(chan interface{}, size)} }
func (goroutinePool *goroutinePool) Get() { goroutinePool.c <- struct{}{} }
func (goroutinePool *goroutinePool) Release() { <-goroutinePool.c }
func withGoroutinePool() { pool = newGoroutinePool(100) ticker := time.NewTicker(time.Second) for { select { case <-ticker.C: fmt.Println(time.Now().String(), runtime.NumGoroutine()) break default: pool.Get() go func() { sleep() pool.Release() }() } } }
func main() { withGoroutinePool() }
func sleep() { time.Sleep(100 * time.Millisecond) }
|
- 输出结果如下所示,可以看出 Goroutine 的数量在 100 左右
1 2 3 4 5 6 7 8 9 10 11
| ➜ aaa git:(dev) ✗ go run main.go 2020-02-10 22:23:57.4038 +0800 CST m=+1.017452302 45 2020-02-10 22:23:58.420406 +0800 CST m=+2.034076062 38 2020-02-10 22:23:59.450896 +0800 CST m=+3.064585392 86 2020-02-10 22:24:00.463936 +0800 CST m=+4.077642981 80 2020-02-10 22:24:01.480972 +0800 CST m=+5.094697456 71 2020-02-10 22:24:02.398438 +0800 CST m=+6.012179639 101 2020-02-10 22:24:03.416983 +0800 CST m=+7.030743402 88 2020-02-10 22:24:04.444314 +0800 CST m=+8.058093131 3 2020-02-10 22:24:05.457963 +0800 CST m=+9.071760019 78 ^Csignal: interrupt
|