基準(zhǔn)測(cè)試,是一種測(cè)試代碼性能的方法,比如你有多種不同的方案,都可以解決問(wèn)題,那么到底是那種方案性能更好呢?這時(shí)候基準(zhǔn)測(cè)試就派上用場(chǎng)了。
創(chuàng)新互聯(lián)專(zhuān)注于含山企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站建設(shè),商城系統(tǒng)網(wǎng)站開(kāi)發(fā)。含山網(wǎng)站建設(shè)公司,為含山等地區(qū)提供建站服務(wù)。全流程按需求定制制作,專(zhuān)業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)專(zhuān)業(yè)和態(tài)度為您提供的服務(wù)基準(zhǔn)測(cè)試主要是通過(guò)測(cè)試CPU和內(nèi)存的效率問(wèn)題,來(lái)評(píng)估被測(cè)試代碼的性能,進(jìn)而找到更好的解決方案。比如鏈接池的數(shù)量不是越多越好,那么哪個(gè)值才是最優(yōu)值呢,這就需要配合基準(zhǔn)測(cè)試不斷調(diào)優(yōu)了。
基準(zhǔn)測(cè)試代碼的編寫(xiě)和單元測(cè)試非常相似,它也有一定的規(guī)則,我們先看一個(gè)示例。
itoa_test.go
func BenchmarkSprintf(b *testing.B){
num:=10
b.ResetTimer()
for i:=0;i }
這是一個(gè)基準(zhǔn)測(cè)試的例子,從中我們可以看出以下規(guī)則:
基準(zhǔn)測(cè)試的代碼文件必須以_test.go結(jié)尾。
基準(zhǔn)測(cè)試的函數(shù)必須以Benchmark開(kāi)頭,必須是可導(dǎo)出的。
基準(zhǔn)測(cè)試函數(shù)必須接受一個(gè)指向Benchmark類(lèi)型的指針作為唯一參數(shù)。
基準(zhǔn)測(cè)試函數(shù)不能有返回值。
b.ResetTimer是重置計(jì)時(shí)器,這樣可以避免for循環(huán)之前的初始化代碼的干擾。
最后的for循環(huán)很重要,被測(cè)試的代碼要放到循環(huán)里。
b.N是基準(zhǔn)測(cè)試框架提供的,表示循環(huán)的次數(shù),因?yàn)樾枰磸?fù)調(diào)用測(cè)試的代碼,才可以評(píng)估性能。
下面我們運(yùn)行下基準(zhǔn)測(cè)試,看看效果。
? hello go test -bench=. -run=none
BenchmarkSprintf-8 20000000 117 ns/op
PASS
ok flysnow.org/hello 2.474s
運(yùn)行基準(zhǔn)測(cè)試也要使用go test命令,不過(guò)我們要加上-bench=標(biāo)記,它接受一個(gè)表達(dá)式作為參數(shù),匹配基準(zhǔn)測(cè)試的函數(shù),.表示運(yùn)行所有基準(zhǔn)測(cè)試。
因?yàn)槟J(rèn)情況下go test會(huì)運(yùn)行單元測(cè)試,為了防止單元測(cè)試的輸出影響我們查看基準(zhǔn)測(cè)試的結(jié)果,可以使用-run=匹配一個(gè)從來(lái)沒(méi)有的單元測(cè)試方法,過(guò)濾掉單元測(cè)試的輸出,我們這里使用none,因?yàn)槲覀兓旧喜粫?huì)創(chuàng)建這個(gè)名字的單元測(cè)試方法。
下面著重解釋下說(shuō)出的結(jié)果,看到函數(shù)后面的-8了嗎?這個(gè)表示運(yùn)行時(shí)對(duì)應(yīng)的GOMAXPROCS的值。接著的20000000表示運(yùn)行for循環(huán)的次數(shù),也就是調(diào)用被測(cè)試代碼的次數(shù),最后的117 ns/op表示每次需要話費(fèi) 117 納秒。
以上是測(cè)試時(shí)間默認(rèn)是 1 秒,也就是 1 秒的時(shí)間,調(diào)用兩千萬(wàn)次,每次調(diào)用花費(fèi) 117 納秒。如果想讓測(cè)試運(yùn)行的時(shí)間更長(zhǎng),可以通過(guò)-benchtime指定,比如 3 秒。
? hello go test -bench=. -benchtime=3s -run=none
BenchmarkSprintf-8 50000000 109 ns/op
PASS
ok flysnow.org/hello 5.628s
可以發(fā)現(xiàn),我們加長(zhǎng)了測(cè)試時(shí)間,測(cè)試的次數(shù)變多了,但是最終的性能結(jié)果:每次執(zhí)行的時(shí)間,并沒(méi)有太大變化。一般來(lái)說(shuō)這個(gè)值最好不要超過(guò)3秒,意義不大。
上面那個(gè)基準(zhǔn)測(cè)試的例子,其實(shí)是一個(gè)int類(lèi)型轉(zhuǎn)為string類(lèi)型的例子,標(biāo)準(zhǔn)庫(kù)里還有幾種方法,我們看下哪種性能更加。
func BenchmarkSprintf(b *testing.B){
num:=10
b.ResetTimer()
for i:=0;i }
運(yùn)行基準(zhǔn)測(cè)試,看看結(jié)果:
? 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
從結(jié)果上看strconv.FormatInt函數(shù)是最快的,其次是strconv.Itoa,然后是fmt.Sprintf最慢,前兩個(gè)函數(shù)性能達(dá)到了最后一個(gè)的 3 倍多。那么最后一個(gè)為什么這么慢的,我們?cè)偻ㄟ^(guò)-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可以提供每次操作分配內(nèi)存的次數(shù),以及每次操作分配的字節(jié)數(shù)。從結(jié)果我們可以看到,性能高的兩個(gè)函數(shù),每次操作都是進(jìn)行 1 次內(nèi)存分配,而最慢的那個(gè)要分配 2 次;性能高的每次操作分配 2 個(gè)字節(jié)內(nèi)存,而慢的那個(gè)函數(shù)每次需要分配 16 字節(jié)的內(nèi)存。從這個(gè)數(shù)據(jù)我們就知道它為什么這么慢了,內(nèi)存分配都占用都太高。
在代碼開(kāi)發(fā)中,對(duì)于我們要求性能的地方,編寫(xiě)基準(zhǔn)測(cè)試非常重要,這有助于我們開(kāi)發(fā)出性能更好的代碼。不過(guò)性能、可用性、復(fù)用性等也要有一個(gè)相對(duì)的取舍,不能為了追求性能而過(guò)度優(yōu)化。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。