溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Go語(yǔ)言之基準(zhǔn)測(cè)試

發(fā)布時(shí)間:2020-08-04 04:06:14 來(lái)源:網(wǎng)絡(luò) 閱讀:442 作者:baby神 欄目:編程語(yǔ)言
什么是基準(zhǔn)測(cè)試


基準(zhǔn)測(cè)試,是一種測(cè)試代碼性能的方法,比如你有多種不同的方案,都可以解決問(wèn)題,那么到底是那種方案性能更好呢?這時(shí)候基準(zhǔn)測(cè)試就派上用場(chǎng)了。


基準(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è)試


基準(zhǔn)測(cè)試代碼的編寫和單元測(cè)試非常相似,它也有一定的規(guī)則,我們先看一個(gè)示例。


itoa_test.go


func BenchmarkSprintf(b *testing.B){
    num:=10
    b.ResetTimer()
    for i:=0;i<b.N;i++{
        fmt.Sprintf("%d",num)
    }
}


這是一個(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類型的指針作為唯一參數(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秒,意義不大。


性能對(duì)比


上面那個(gè)基準(zhǔn)測(cè)試的例子,其實(shí)是一個(gè)int類型轉(zhuǎn)為string類型的例子,標(biāo)準(zhǔn)庫(kù)里還有幾種方法,我們看下哪種性能更加。


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)
    }
}


運(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ì)于我們要求性能的地方,編寫基準(zhǔn)測(cè)試非常重要,這有助于我們開(kāi)發(fā)出性能更好的代碼。不過(guò)性能、可用性、復(fù)用性等也要有一個(gè)相對(duì)的取舍,不能為了追求性能而過(guò)度優(yōu)化。


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI