- Go語(yǔ)言精進(jìn)之路:從新手到高手的編程思想、方法和技巧(2)
- 白明
- 1408字
- 2022-01-04 17:42:26
46.3 使用性能基準(zhǔn)比較工具
現(xiàn)在我們已經(jīng)可以通過(guò)Go原生提供的性能基準(zhǔn)測(cè)試為被測(cè)對(duì)象建立性能基準(zhǔn)了。但被測(cè)代碼更新前后的性能基準(zhǔn)比較依然要靠人工計(jì)算和肉眼比對(duì),十分不方便。為此,Go核心團(tuán)隊(duì)先后開(kāi)發(fā)了兩款性能基準(zhǔn)比較工具:benchcmp(https://github.com/golang/tools/tree/master/cmd/benchcmp)和benchstat(https://github.com/golang/perf/tree/master/benchstat)。
1. benchcmp
benchcmp上手快,簡(jiǎn)單易用,對(duì)于輸出的比較結(jié)果我們無(wú)須參考文檔幫助即可自行解讀。下面看一個(gè)使用benchcmp進(jìn)行性能基準(zhǔn)比較的例子。
// chapter8/sources/benchmark-compare/strcat_test.go var sl = []string{ "Rob Pike ", "Robert Griesemer ", "Ken Thompson ", } func Strcat(sl []string) string { return concatStringByOperator(sl) } func concatStringByOperator(sl []string) string { var s string for _, v := range sl { s += v } return s } func concatStringByJoin(sl []string) string { return strings.Join(sl, "") } func BenchmarkStrcat(b *testing.B) { for n := 0; n < b.N; n++ { Strcat(sl) } }
上面例子中的被測(cè)目標(biāo)為Strcat。最初Strcat使用通過(guò)Go原生的操作符("+")連接的方式實(shí)現(xiàn)了字符串的連接。我們采集一下它的性能基準(zhǔn)數(shù)據(jù):
$go test -run=NONE -bench . strcat_test.go > old.txt
然后,升級(jí)Strcat的實(shí)現(xiàn),采用strings.Join函數(shù)來(lái)實(shí)現(xiàn)多個(gè)字符串的連接:
func Strcat(sl []string) string { return concatStringByJoin(sl) }
再采集優(yōu)化后的性能基準(zhǔn)數(shù)據(jù):
$go test -run=NONE -bench . strcat_test.go > new.txt
接下來(lái)就輪到benchcmp登場(chǎng)了:
$benchcmp old.txt new.txt benchmark old ns/op new ns/op delta BenchmarkStrcat-8 92.4 49.6 -46.32%
我們看到,benchcmp接受被測(cè)代碼更新前后的兩次性能基準(zhǔn)測(cè)試結(jié)果文件——old.txt和new.txt,并將這兩個(gè)文件中的相同基準(zhǔn)測(cè)試(比如這里的BenchmarkStrcat)的輸出結(jié)果進(jìn)行比較。
如果使用-count對(duì)BenchmarkStrcat執(zhí)行多次,那么benchcmp給出的結(jié)果如下:
$go test -run=NONE -count 5 -bench . strcat_test.go > old.txt $go test -run=NONE -count 5 -bench . strcat_test.go > new.txt $benchcmp old.txt new.txt benchmark old ns/op new ns/op delta BenchmarkStrcat-8 92.8 51.4 -44.61% BenchmarkStrcat-8 91.9 55.3 -39.83% BenchmarkStrcat-8 96.1 52.6 -45.27% BenchmarkStrcat-8 89.4 50.2 -43.85% BenchmarkStrcat-8 91.2 51.5 -43.53%
如果向benchcmp傳入-best命令行選項(xiàng),benchcmp將分別從old.txt和new.txt中挑選性能最好的一條數(shù)據(jù),然后進(jìn)行比較:
$benchcmp -best old.txt new.txt benchmark old ns/op new ns/op delta BenchmarkStrcat-8 89.4 50.2 -43.85%
benchcmp還可以按性能基準(zhǔn)數(shù)據(jù)前后變化的大小對(duì)輸出結(jié)果進(jìn)行排序(通過(guò)-mag命令行選項(xiàng)):
$benchcmp -mag old.txt new.txt benchmark old ns/op new ns/op delta BenchmarkStrcat-8 96.1 52.6 -45.27% BenchmarkStrcat-8 92.8 51.4 -44.61% BenchmarkStrcat-8 89.4 50.2 -43.85% BenchmarkStrcat-8 91.2 51.5 -43.53% BenchmarkStrcat-8 91.9 55.3 -39.83%
不過(guò)性能基準(zhǔn)測(cè)試的輸出結(jié)果受到很多因素的影響,比如:同一測(cè)試的運(yùn)行次數(shù);性能基準(zhǔn)測(cè)試與其他正在運(yùn)行的程序共享一臺(tái)機(jī)器;運(yùn)行測(cè)試的系統(tǒng)本身就在虛擬機(jī)上,與其他虛擬機(jī)共享硬件;現(xiàn)代機(jī)器的一些節(jié)能和功率縮放(比如CPU的自動(dòng)降頻和睿頻)等。這些因素都會(huì)造成即便是對(duì)同一個(gè)基準(zhǔn)測(cè)試進(jìn)行多次運(yùn)行,輸出的結(jié)果也可能有較大偏差。但benchcmp工具并不關(guān)心這些結(jié)果數(shù)據(jù)在統(tǒng)計(jì)學(xué)層面是否有效,只對(duì)結(jié)果做簡(jiǎn)單比較。
2. benchstat
為了提高對(duì)性能基準(zhǔn)數(shù)據(jù)比較的科學(xué)性,Go核心團(tuán)隊(duì)又開(kāi)發(fā)了benchstat這款工具以替代benchcmp。下面用benchstat比較一下上面例子中的性能基準(zhǔn)數(shù)據(jù):
$benchstat old.txt new.txt name old time/op new time/op delta Strcat-8 92.3ns ± 4% 52.2ns ± 6% -43.43% (p=0.008 n=5+5)
我們看到,即便old.txt和new.txt中各自有5次運(yùn)行的數(shù)據(jù),benchstat也不會(huì)像benchcmp那樣輸出5行比較結(jié)果,而是輸出一行經(jīng)過(guò)統(tǒng)計(jì)學(xué)方法處理后的比較結(jié)果。以第二列數(shù)據(jù)92.3ns ± 4%為例,這是benchcmp對(duì)old.txt中的數(shù)據(jù)進(jìn)行處理后的結(jié)果,其中±4%是樣本數(shù)據(jù)中最大值和最小值距樣本平均值的最大偏差百分比。如果這個(gè)偏差百分比大于5%,則說(shuō)明樣本數(shù)據(jù)質(zhì)量不佳,有些樣本數(shù)據(jù)是不可信的。由此可以看出,這里new.txt中的樣本數(shù)據(jù)是質(zhì)量不佳的。
benchstat輸出結(jié)果的最后一列(delta)為兩次基準(zhǔn)測(cè)試對(duì)比的變化量。我們看到,采用strings.Join方法連接字符串的平均耗時(shí)比采用原生操作符連接字符串短43%,這個(gè)指標(biāo)后面括號(hào)中的p=0.008是一個(gè)用于衡量?jī)蓚€(gè)樣本集合的均值是否有顯著差異的指標(biāo)。benchstat支持兩種檢驗(yàn)算法:一種是UTest(Mann Whitney UTest,曼-惠特尼U檢驗(yàn)),UTest是默認(rèn)的檢驗(yàn)算法;另外一種是Welch T檢驗(yàn)(TTest)。一般p值小于0.05的結(jié)果是可接受的。
上述兩款工具都支持對(duì)內(nèi)存分配數(shù)據(jù)情況的前后比較,這里以benchstat為例:
$go test -run=NONE -count 5 -bench . strcat_test.go -benchmem > old_with_mem.txt $go test -run=NONE -count 5 -bench . strcat_test.go -benchmem > new_with_mem.txt $benchstat old_with_mem.txt new_with_mem.txt name old time/op new time/op delta Strcat-8 90.5ns ± 1% 50.6ns ± 2% -44.14% (p=0.008 n=5+5) name old alloc/op new alloc/op delta Strcat-8 80.0B ± 0% 48.0B ± 0% -40.00% (p=0.008 n=5+5) name old allocs/op new allocs/op delta Strcat-8 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.008 n=5+5)
關(guān)于內(nèi)存分配情況對(duì)比的輸出獨(dú)立于執(zhí)行時(shí)間的輸出,但結(jié)構(gòu)上是一致的(輸出列含義相同),這里就不再贅述了。
Go核心團(tuán)隊(duì)已經(jīng)給benchcmp工具打上了“deprecation”(不建議使用)的標(biāo)簽,因此建議大家使用benchstat來(lái)進(jìn)行性能基準(zhǔn)數(shù)據(jù)的比較。
- Python數(shù)據(jù)分析入門與實(shí)戰(zhàn)
- ASP.NET MVC4框架揭秘
- Python入門很簡(jiǎn)單
- LabVIEW入門與實(shí)戰(zhàn)開(kāi)發(fā)100例
- Visual Basic編程:從基礎(chǔ)到實(shí)踐(第2版)
- Mastering Scientific Computing with R
- Python機(jī)器學(xué)習(xí)實(shí)戰(zhàn)
- TypeScript項(xiàng)目開(kāi)發(fā)實(shí)戰(zhàn)
- 從0到1:Python數(shù)據(jù)分析
- 組態(tài)軟件技術(shù)與應(yīng)用
- Active Directory with PowerShell
- Python程序設(shè)計(jì)與算法基礎(chǔ)教程(第2版)(微課版)
- 計(jì)算機(jī)應(yīng)用基礎(chǔ)教程(Windows 7+Office 2010)
- Advanced Python Programming
- Python面試通關(guān)寶典