基準測試,是一種測試代碼性能的方法,好比你有多種不一樣的方案,均可以解決問題,那麼究竟是那種方案性能更好呢?這時候基準測試就派上用場了。框架
基準測試主要是經過測試CPU和內存的效率問題,來評估被測試代碼的性能,進而找到更好的解決方案。好比連接池的數量不是越多越好,那麼哪一個值纔是最優值呢,這就須要配合基準測試不斷調優了。函數
基準測試代碼的編寫和單元測試很是類似,它也有必定的規則,咱們先看一個示例。性能
itoa_test.go單元測試
package gotest import ( "fmt" "testing" ) //itoa_test.go func BenchmarkSprintf(b *testing.B) { num := 10 b.ResetTimer() for i := 0; i < b.N; i++ { fmt.Sprintf("%d", num) } }
這是一個基準測試的例子,從中咱們能夠看出如下規則:測試
_test.go
結尾Benchmark
開頭,必須是可導出的b.ResetTimer
是重置計時器,這樣能夠避免for
循環以前的初始化代碼的干擾b.N
是基準測試框架提供的,表示循環的次數,由於須要反覆調用測試的代碼,才能夠評估性能
運行基準測試也要使用go test
命令,不過咱們要加上-bench=
標記,它接受一個表達式做爲參數,匹配基準測試的函數,.表示運行全部基準測試。優化
由於默認狀況下go test
會運行單元測試,爲了防止單元測試的輸出影響咱們查看基準測試的結果,可使用-run=
匹配一個歷來沒有的單元測試方法,過濾掉單元測試的輸出,咱們這裏使用none
,由於咱們基本上不會建立這個名字的單元測試方法。spa
下面着重解釋下說出的結果,看到函數後面的-2
了嗎?這個表示運行時對應的GOMAXPROCS
的值。接着的5000000表示運行for
循環的次數,也就是調用被測試代碼的次數,最後的290 ns/op表示每次須要話費290納秒。指針
以上是測試時間默認是1秒,也就是1秒的時間,調用5000000次,每次調用花費290納秒。若是想讓測試運行的時間更長,能夠經過-benchtime
指定,好比3秒。code
能夠發現,咱們加長了測試時間,測試的次數變多了,可是最終的性能結果:每次執行的時間,並無太大變化。通常來講這個值最好不要超過3秒,意義不大。orm
上面那個基準測試的例子,實際上是一個int
類型轉爲string
類型的例子,標準庫裏還有幾種方法,咱們看下哪一種性能更加。
package gotest import ( "fmt" "strconv" "testing" ) func BenchmarkSprintf(b *testing.B) { num := 10 b.ResetTimer() for i := 0; i < b.N; i++ { fmt.Sprintf("%d", num) } } func BenchmarkFormat(b *testing.B) { num := int64(10) b.ResetTimer() for i := 0; i < b.N; i++ { strconv.FormatInt(num, 10) } } func BenchmarkItoa(b *testing.B) { num := 10 b.ResetTimer() for i := 0; i < b.N; i++ { strconv.Itoa(num) } }
運行基準測試,看看結果
從結果上看strconv.FormatInt
函數是最快的,其次是strconv.Itoa
,而後是fmt.Sprintf
最慢,前兩個函數性能達到了最後一個的10倍多。那麼最後一個爲何這麼慢的,咱們再經過-benchmem
找到根本緣由。
-benchmem
能夠提供每次操做分配內存的次數,以及每次操做分配的字節數。allocs/op 表示每次操做從堆上分配內存的次數。B/op 表示每次操做分配的字節數。 從結果咱們能夠看到,性能高的兩個函數,每次操做都是進行0次內存分配,而最慢的那個要分配2次;性能高的每次操做分配8個字節內存,而慢的那個函數每次須要分配0字節的內存。從這個數據咱們就知道它爲何這麼慢了,內存分配都佔用都過高。