注意,轉發的文章時間爲2011年,時間比較老了,因此數據只作參考。能夠體現出golang的優點。
原文在此:http://en.munknex.net/2011/12/golang-goroutines-performance.htmlhtml
————————–翻譯分割線————————–golang
在這篇文章裏,我將嘗試評估 goroutine 的性能。goroutine 是相似輕量級線程的東西。爲了提供原生的多任務,它(協同 channel 一塊兒)被內建於Go中。多線程
文檔告訴咱們:併發
它其實是在同一個地址空間裏建立成百上千個 goroutine。函數
所以,這個文章的重點就是測試並明確在如此巨大的併發運行函數的狀況下所能承受的性能壓力上限。
性能
建立一個新的goroutine所需空間並未記錄在文檔中。只是說須要幾千字節。在不一樣的機制下測試,幫助確認這個數值爲4—4.5kB。所以,5GB差很少足夠運行一百萬個goroutine。測試
讓咱們算算在一個 goroutine 裏運行函數會損失多少的性能吧。可能你已經知道這很是簡單——只要在函數調用前添加 go 關鍵字:spa
go testFunc()
|
goroutine 複用於線程。默認狀況下,若是沒有設定 GOMAXPROCS 環境變量,程序只使用一個線程。爲了利用所有 CPU 內核,則必須制定它的值。例如:.net
export
GOMAXPROCS=2
|
這個值在運行時使用。所以沒有必要在每次修改這個值以後,從新編譯程序。線程
以個人推斷,大多數時間花費在建立 goroutine,切換它們,以及從一個線程遷移 goroutine 到另外的線程,還有在不一樣的線程之間的 goroutine 進行通信。爲了不無盡的論述,讓咱們從僅用一個線程的狀況開始。
全部測試都是在個人 nettop(譯註:英特爾公司的低成本簡易臺式機解決方案)上完成的:
Atom D525 Dual Core 1.8 GHz
4Gb DDR3
Go r60.3
Arch Linux x86_64
這是測試函數生成器:
func genTest (n
int
) func (res chan <- interface {}) {
return
func(res chan <- interface {}) {
for
i := 0; i < n; i++ {
math.Sqrt(13)
}
res <-
true
}
}
|
而後這裏是一系列分別計算 sqrt(13) 一、十、100、1000 和 5000 次的函數集合:
testFuncs := [] func (chan <- interface {}) { genTest(1), genTest(10), genTest(100), genTest(1000), genTest(5000) }
|
我將每一個函數在循環中執行 X 遍,而後在 goroutine 中執行 X 遍。而後比較結果。固然,應當留意垃圾回收。爲了下降其帶來的影響,我在 goroutine 結束後顯式調用了 runtime.GC() 並記錄結束時間。固然,爲了測試精確性,每一個測試執行了許多遍。整個運行時間用了大約 16 小時。
export
GOMAXPROCS=1
|
圖表顯示在 goroutine 中運行的 sqrt() 計算工做大約比在函數中運行慢四倍。
來看看剩餘的四個函數的狀況:
你會注意到,即便併發執行70萬 goroutine 也不會使得性能降低到 80% 如下。如今是最值得敬佩的地方。從 sqrt()x1000 開始,整體消耗低於 2%。5000 次——只有 1%。看起來這個數值與 goroutine 的數量無關!所以惟一的制約因素是內存。
若是互不依賴的代碼的執行時間高於計算平方跟的10倍,而且你但願它併發執行,應堅決果斷的讓其在 goroutine 中運行。雖然,能夠輕鬆的將10或者100個這樣的代碼放在一塊兒,不過損失的性能僅僅分別是 20% 和 2%。
如今來看看當咱們但願使用若干個處理器內核時的狀況。在個人用例中是 2 個:
export
GOMAXPROCS=2
|
再次執行咱們的測試程序:
這裏你會發現,儘管內核數增長了一倍,可是前兩個函數的運行時間卻增長了!這很可能是在線程之間移動比執行它們的開銷要大得多。:)當前的調度器還不能處理,不過 Go 的開發者承諾在將來會解決這種狀況。
你已經看到了,最後的兩個函數徹底使用了兩個核。在個人 nettop 上,他們的執行時間分別是 ~45µs 和 ~230µs。
儘管這是一個年輕的語言,而且有着一個臨時的調度器實現,goroutine 的性能讓人以爲興奮。尤爲是與 Go 的簡單易用結合起來的時候。這令我印象深入。感謝 Go 開發團隊!
當運行時間少於 1µs 我會在執行 goroutine 以前深思熟慮一下,而若是運行時間超過 1ms,那就決不猶豫的使用 goroutine 了。:)