上周我写了一篇文章Go 每日一库之 ants,深刻剖析了ants
这个 goroutine 池的实现。在反复阅读了多遍panjf2000关于ants
的起源的文章——GMP 并发调度器深度解析之手撸一个高性能 goroutine pool,我感受收获满满。这篇文章对于理解 Go 的 goroutine 并发机制有很大的参考价值,强烈建议一读。而后我花了几个小时时间详细阅读了ants
的源码,代码写的很棒,很是优美。然后我写了一遍文章分析了ants
的源码,见ants
源码赏析。在写介绍ants
的文章和深刻阅读源码过程当中,网上的资料说起 Go 语言中 goroutine 池的实现,时常会带上tunny
这个库。因而,我又去研究了tunny
的源码,产出一篇文章Go 每日一库之 tunny。git
在阅读tunny
源码时,我发现有个方法的实现有些问题。我也在Go 每日一库之 tunny中也指出了:github
咱们知道 slice 结构中有一个指向数组的指针。假设一开始tunny
中有 5 个 worker,示意图以下:golang
数组中每一个元素都是一个指针,指向一个worker
结构。而后咱们使用s := s[:4]
缩容了,进变成了下面这样:数组
如今最后一个元素没法经过切片访问了,可是又被底层数组引用着,没法被 Go 运行时的 gc 清理掉,360 软件管家都不行。这就有内存泄漏了。虽然这个泄漏并不严重,一是由于量不可能很大,由于 worker 数量有限,二是下次扩容后位置被覆盖就能够释放原 worker 了(由于没有引用它的指针了)。微信
ants
源码中也有相似的操做,可是会将缩容掉的元素置为nil
。例如worker_stack.go
中的reset()
方法:并发
func (wq *workerStack) reset() { for i := 0; i < wq.len(); i++ { wq.items[i].task <- nil wq.items[i] = nil } wq.items = wq.items[:0] }
肯定了问题。我先 fork 了tunny
的仓库。点击 fork 按钮:dom
然后将 fork 后的我本身的仓库下载:性能
$ git clone git@github.com:darjun/tunny.git
修改代码,commit,push 到个人远程仓库。下面是我所作的改动:学习
而后去tunny
源仓库,点击Pull Request
按钮。而后点击右侧的New pull request
按钮:spa
新建一个 PR,而后点击compare across forks
,选择个人 fork:
选择我作修改的那次提交,而后填写信息,提交,因为我已经提交了 PR。此次比较就没有差别了。
而后等待做者合并。一天后,做者合并了此次修改:
GitHub 提交 PR 并不难,大到新增特性,小到一个拼写错误,均可以提 PR。相信很多人都据说过,Linus Torvalds 亲自合并了一个来自 11 岁小孩提交的关于 Linux 源码注释中拼写错误的 PR。
GitHub 上 star 不少的项目并不是完美,确定也有不少值得改进的地方。因此阅读源码时须要带有必定的怀疑精神,不要把什么奉为圭臬。
你们若是发现好玩、好用的 Go 语言库,欢迎到 Go 每日一库 GitHub 上提交 issue😄
欢迎关注个人微信公众号【GoUpUp】,共同窗习,一块儿进步~