您好,登錄后才能下訂單哦!
基準測試,是一種測試代碼性能的方法,比如你有多種不同的方案,都可以解決問題,那么到底是那種方案性能更好呢?這時候基準測試就派上用場了。
基準測試主要是通過測試CPU和內存的效率問題,來評估被測試代碼的性能,進而找到更好的解決方案。比如鏈接池的數量不是越多越好,那么哪個值才是最優值呢,這就需要配合基準測試不斷調優了。
基準測試代碼的編寫和單元測試非常相似,它也有一定的規則,我們先看一個示例。
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開頭,必須是可導出的。
基準測試函數必須接受一個指向Benchmark類型的指針作為唯一參數。
基準測試函數不能有返回值。
b.ResetTimer是重置計時器,這樣可以避免for循環之前的初始化代碼的干擾。
最后的for循環很重要,被測試的代碼要放到循環里。
b.N是基準測試框架提供的,表示循環的次數,因為需要反復調用測試的代碼,才可以評估性能。
下面我們運行下基準測試,看看效果。
? hello go test -bench=. -run=none
BenchmarkSprintf-8 20000000 117 ns/op
PASS
ok flysnow.org/hello 2.474s
運行基準測試也要使用go test命令,不過我們要加上-bench=標記,它接受一個表達式作為參數,匹配基準測試的函數,.表示運行所有基準測試。
因為默認情況下go test會運行單元測試,為了防止單元測試的輸出影響我們查看基準測試的結果,可以使用-run=匹配一個從來沒有的單元測試方法,過濾掉單元測試的輸出,我們這里使用none,因為我們基本上不會創建這個名字的單元測試方法。
下面著重解釋下說出的結果,看到函數后面的-8了嗎?這個表示運行時對應的GOMAXPROCS的值。接著的20000000表示運行for循環的次數,也就是調用被測試代碼的次數,最后的117 ns/op表示每次需要話費 117 納秒。
以上是測試時間默認是 1 秒,也就是 1 秒的時間,調用兩千萬次,每次調用花費 117 納秒。如果想讓測試運行的時間更長,可以通過-benchtime指定,比如 3 秒。
? hello go test -bench=. -benchtime=3s -run=none
BenchmarkSprintf-8 50000000 109 ns/op
PASS
ok flysnow.org/hello 5.628s
可以發現,我們加長了測試時間,測試的次數變多了,但是最終的性能結果:每次執行的時間,并沒有太大變化。一般來說這個值最好不要超過3秒,意義不大。
上面那個基準測試的例子,其實是一個int類型轉為string類型的例子,標準庫里還有幾種方法,我們看下哪種性能更加。
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)
}
}
運行基準測試,看看結果:
? hello go test -bench=. -run=none BenchmarkSprintf-8 20000000 117 ns/op
BenchmarkFormat-8 50000000 33.3 ns/op
BenchmarkItoa-8 50000000 34.9 ns/op
PASS
ok flysnow.org/hello 5.951s
從結果上看strconv.FormatInt函數是最快的,其次是strconv.Itoa,然后是fmt.Sprintf最慢,前兩個函數性能達到了最后一個的 3 倍多。那么最后一個為什么這么慢的,我們再通過-benchmem找到根本原因。
? hello go test -bench=. -benchmem -run=none
BenchmarkSprintf-8 20000000 110 ns/op 16 B/op 2 allocs/op
BenchmarkFormat-8 50000000 31.0 ns/op 2 B/op 1 allocs/op
BenchmarkItoa-8 50000000 33.1 ns/op 2 B/op 1 allocs/op
PASS
ok flysnow.org/hello 5.610s
-benchmem可以提供每次操作分配內存的次數,以及每次操作分配的字節數。從結果我們可以看到,性能高的兩個函數,每次操作都是進行 1 次內存分配,而最慢的那個要分配 2 次;性能高的每次操作分配 2 個字節內存,而慢的那個函數每次需要分配 16 字節的內存。從這個數據我們就知道它為什么這么慢了,內存分配都占用都太高。
在代碼開發中,對于我們要求性能的地方,編寫基準測試非常重要,這有助于我們開發出性能更好的代碼。不過性能、可用性、復用性等也要有一個相對的取舍,不能為了追求性能而過度優化。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。