上週我寫了一篇文章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】,共同窗習,一塊兒進步~