每日一博 | 如何优雅的控制goroutine的数量

1,为什么要控制goroutine的数量?goroutine固然好,但是数量太多了,往往会带来很多麻烦,比如耗尽系统资源导致程序崩溃,或者CPU使用率过高导致系统忙不过来。比如:

` for i:=0; i < 10000; i++ { go work() }
**2,用什么方法控制goroutine的数量?** 要在每一次执行go之前判断goroutine的数量,如果数量超了,就要阻塞go的执行。第一时间想到的就是使用通道。每次执行的go之前向通道写入值,直到通道满的时候就阻塞了,如下: ``

var ch chan int

func work() { //do something <-ch }

func main() { ch = make(chan int, 10) for i:=0; i < 10000; i++ { ch <- 1 go work() } }

` 这样每次同时运行的goroutine就被限制为10个了。但是新的问题出现了,因为并不是所有的goroutine都执行完了,在main函数退出之后,还有一些goroutine没有执行完就被强制结束了。这个时候我们就需要用到sync.WaitGroup。使用WaitGroup等待所有的goroutine退出。如下:

` var wg *sync.WaitGroup

func work() { defer wg.Done() //do something }

func main() { wg = &sync.WaitGroup{} for i:=0; i < 10000; i++ { wg.Add(1) go work() } wg.Wait()//等待所有goroutine退出 }

` **3,优雅的使用并控制goroutine的数量** 综上所述,我们封装一下,代码如下:

` package gpool

import ( "sync" )

type pool struct { queue chan int wg *sync.WaitGroup }

func New(size int) *pool { if size <= 0 { size = 1 } return &pool{ queue: make(chan int, size), wg: &sync.WaitGroup{}, } }

func (p *pool) Add(delta int) { for i := 0; i<delta; i++ { p.queue<- 1 } for i := 0; i > delta; i– { <-p.queue } p.wg.Add(delta) }

func (p *pool) Done() { <-p.queue p.wg.Done() }

func (p *pool) Wait() { p.wg.Wait() }

` 来段测试代码:

` package gpool_test

import ( "runtime" "testing" "time" "trans/gpool" )

func Test_Example(t *testing.T) { pool := gpool.New(100) println(runtime.NumGoroutine()) for i := 0; i < 1000; i++ { pool.Add(1) go func() { time.Sleep(time.Second) println(runtime.NumGoroutine()) pool.Done() }() } pool.Wait() println(runtime.NumGoroutine()) } “` good job,Over~

原文  http://my.oschina.net/xlplbo/blog/682884?fromerr=SYH7Whwn

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » 每日一博 | 如何优雅的控制goroutine的数量

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址