前言:

先聊下线程池,线程池存在是为了规避频繁的线程创建和销毁的开销,那么协程池呢? 我们知道在go的gmp体系下,协程的创建开销是很低的。几年前社区里不少开源项目里,为了规避协程的创建销毁的开销, 重复morestack扩充栈空间问题来实现协程池。比如风靡一时的fasthttp框架和tidb分布式数据库也引用了协程池。

但去年我在pingcap的tidb里看到了猫哥提的pr, 里面详细对比了 加协程池和直接 go func(){}的性能对比,直接 go newproc1的性能要比加协程池还高一些。想想也能理解,协程池也是有channel的开销的,channel里不仅有锁消耗,而且还有因阻塞造成的调度消耗。

我们用golang协程池的场景?

回到我们的主题,我们的场景主要是并发控制! 对的,用协程池来控制下游的并发。比如下游的某个api同一时间最多可以抗住200个长轮询请求。你可以在协程池里控制最多200个goroutine来处理。
当然你也可以使用信号量来控制,没有选用信号量的原因主要是不能动态的控制worker,没有缓冲队列的设计。当然,这是个伪命题。
这里不能用令牌和漏桶来限制并发,因为你不确定请求啥时候执行完,如令牌桶不好控制好令牌的生成速度。

go协程池的实现:

我自己实现了一个go协程池, 代码扔到github里了,有兴趣的可以看看。https://github.com/rfyiamcool/gpool , 求点赞。

实现的思路很简单,就是需要一个channel做缓冲池,然后预先开启几个goroutine消费该channel。通过回调的方法来实现异步和阻塞方法。

总结:

原本是打算写一个golang hystrix熔断器的,看过java hystrix熔断器的实现,第一个步骤就是构建线程池。但写着写着,懒了,就先协程池吧。