- Go語言精進之路:從新手到高手的編程思想、方法和技巧(2)
- 白明
- 640字
- 2022-01-04 17:42:26
46.1 性能基準測試在Go語言中是“一等公民”
在前文中,我們已經接觸過許多性能基準測試。和上一條所講的模糊測試的境遇不同,性能基準測試在Go語言中是和普通的單元測試一樣被原生支持的,得到的是“一等公民”的待遇。我們可以像對普通單元測試那樣在*_test.go文件中創建被測對象的性能基準測試,每個以Benchmark前綴開頭的函數都會被當作一個獨立的性能基準測試:
func BenchmarkXxx(b *testing.B) { //... }
下面是一個對多種字符串連接方法的性能基準測試(改編自第15條):
// chapter8/sources/benchmark_intro_test.go var sl = []string{ "Rob Pike ", "Robert Griesemer ", "Ken Thompson ", } func concatStringByOperator(sl []string) string { var s string for _, v := range sl { s += v } return s } func concatStringBySprintf(sl []string) string { var s string for _, v := range sl { s = fmt.Sprintf("%s%s", s, v) } return s } func concatStringByJoin(sl []string) string { return strings.Join(sl, "") } func BenchmarkConcatStringByOperator(b *testing.B) { for n := 0; n < b.N; n++ { concatStringByOperator(sl) } } func BenchmarkConcatStringBySprintf(b *testing.B) { for n := 0; n < b.N; n++ { concatStringBySprintf(sl) } } func BenchmarkConcatStringByJoin(b *testing.B) { for n := 0; n < b.N; n++ { concatStringByJoin(sl) } }
上面的源文件中定義了三個性能基準測試:BenchmarkConcatStringByOperator、Benchmark-ConcatStringBySprintf和BenchmarkConcatStringByJoin。我們可以一起運行這三個基準測試:
$go test -bench . benchmark_intro_test.go goos: darwin goarch: amd64 BenchmarkConcatStringByOperator-8 12810092 88.5 ns/op BenchmarkConcatStringBySprintf-8 2777902 432 ns/op BenchmarkConcatStringByJoin-8 23994218 49.7 ns/op PASS ok command-line-arguments 4.117s
也可以通過正則匹配選擇其中一個或幾個運行:
$go test -bench=ByJoin ./benchmark_intro_test.go goos: darwin goarch: amd64 BenchmarkConcatStringByJoin-8 23429586 49.1 ns/op PASS ok command-line-arguments 1.209s
我們關注的是go test輸出結果中第三列的那個值。以BenchmarkConcatStringByJoin為例,其第三列的值為49.1 ns/op,該值表示BenchmarkConcatStringByJoin這個基準測試中for循環的每次循環平均執行時間為49.1 ns(op代表每次循環操作)。這里for循環調用的是concatStringByJoin,即執行一次concatStringByJoin的平均時長為49.1 ns。
性能基準測試還可以通過傳入-benchmem命令行參數輸出內存分配信息(與基準測試代碼中顯式調用b.ReportAllocs的效果是等價的):
$go test -bench=Join ./benchmark_intro_test.go -benchmem goos: darwin goarch: amd64 BenchmarkConcatStringByJoin-8 23004709 48.8 ns/op 48 B/op 1 allocs/op PASS ok command-line-arguments 1.183s
這里輸出的內存分配信息告訴我們,每執行一次concatStringByJoin平均進行一次內存分配,每次平均分配48字節的數據。