前言
在benchmarkgame(世界上最火的性能對比網站)上,Go語言一直有一個槽點,就是極其慢的binary tree性能,執行用時40秒 (我的機器上,16秒),與此對比,Java版本是6秒,那么問題來了:為什么慢得令人發指?我們來深入研究下慢的原因,然后看看能否對其進行改進。
對于binary tree算法中,最耗性能的地方就是海量的node分配和bottomUpTree()遞歸函數的調用,與這兩項對應的go的特性就是gc的goroutine的堆棧分配。
GC
這個世界沒有完美的GC,任何選擇都有代價,一般來說就是低延遲和高吞吐的權衡。
問題描述
Java采用的是分代GC,優點是node的分配非常輕量,缺點就是分代gc需要使用更多的內存空間,同時當對象被移動到tenured堆時,會發生大量的內存拷貝。 Go的gc不是分代的,因此在node的分配上需要消耗更多的資源。Go的gc選擇了超低的延遲,同時犧牲了部分吞吐,對于絕大多數應用來說,Go的選擇是非常正確的,但是對于binary tree這種算法來說,就不是很適合了。
解決方案
針對GC的優化,有兩個通用的解決方案就是提前分配合適的堆棧空間和對象復用。對于binary tree算法,就是Nodes的預先分配和復用。
Goroutine的堆棧
輕量的Goroutine是Go語言的靈魂所在
問題描述
為了讓goroutine盡可能輕量,go僅僅為每個goroutine分配了2KB的初始堆棧大小,在之后Go會根據需要動態的擴展堆棧大小。同樣,對于絕大多數場景,這種選擇都是非常正確的,但是針對binary tree算法,這種選擇就有了一些問題。
Go是在每次函數調用之前檢查goroutine的堆棧大小,如果發現當前堆棧不夠用,就會重新分配一個新的堆棧空間,然后將舊的堆棧拷貝到新的里。這種操作開銷是很小的,但是在binary tree中,bottomUpTree()基本上不做什么工作,調用卻是極其頻繁,這樣一來再小的開銷累積起來也會非常可觀。而且這個函數的調用是深遞歸,當堆棧需要增長時,可能會拷貝幾次,不僅僅是一次!解決方案 將bottomUpTree()改為非遞歸的函數,雖然不易實現,但是還是可以做到的。
新舊Binary tree實現對比
沒有對比,就沒有傷害!
運行用時:
> time go run old.go 20
stretch tree of depth 21 check: -1
2097152 trees of depth 4 check: -2097152
524288 trees of depth 6 check: -524288
131072 trees of depth 8 check: -131072
32768 trees of depth 10 check: -32768
8192 trees of depth 12 check: -8192
2048 trees of depth 14 check: -2048
512 trees of depth 16 check: -512
128 trees of depth 18 check: -128
32 trees of depth 20 check: -32
long lived tree of depth 20 check: -1
real0m16.279s
user1m47.569s
sys0m2.663s
運行用時
time go run new.go 20
stretch tree of depth 21 check: -1
2097152 trees of depth 4 check: -2097152
524288 trees of depth 6 check: -524288
131072 trees of depth 8 check: -131072
32768 trees of depth 10 check: -32768
8192 trees of depth 12 check: -8192
2048 trees of depth 14 check: -2048
512 trees of depth 16 check: -512
128 trees of depth 18 check: -128
32 trees of depth 20 check: -32
long lived tree of depth 20 check: -1
dur: 1.71074946s
real0m1.914s
user0m10.149s
sys0m0.157s
結論
性能從16.28秒提升到了1.91秒,提升巨大!
這里提出的解決方案看似是針對binary tree,其實對于任何GC語言和使用場景來說都是通用的。
牢記這兩種解決方案吧:-內存空間預分配-對象復用
如果您喜歡這篇文章,請點擊喜歡;如果想及時獲得最新的咨詢,請點擊關注。您的支持是對作者都是最大的激勵,萬分感激!By 孫飛