國外網(wǎng)站設(shè)計(jì)參考寧波seo快速優(yōu)化平臺
一、什么是基準(zhǔn)測試(Benchmark)
在 Go 中,基準(zhǔn)測試是通過創(chuàng)建以 Benchmark 開頭的函數(shù),并接收一個 *testing.B 類型的參數(shù)來實(shí)現(xiàn)的。testing.B 提供了控制基準(zhǔn)測試執(zhí)行的接口,比如設(shè)置測試執(zhí)行的次數(shù)、記錄每次執(zhí)行的時間等。
每個基準(zhǔn)測試函數(shù)都必須接受一個 *testing.B 類型的參數(shù)。函數(shù)體內(nèi)通過 b.N來控制基準(zhǔn)測試的執(zhí)行次數(shù),Go 會自動調(diào)整 b.N 的值,確保每次基準(zhǔn)測試運(yùn)行的時間足夠長。
例如:
package mainimport ("testing"
)// 基準(zhǔn)測試函數(shù)
func BenchmarkMyFunction(b *testing.B) {// 這里是測試的代碼,每次循環(huán) b.N 次for i := 0; i < b.N; i++ {// 被測試的函數(shù)或代碼塊_ = "hello"}
}
二、怎么進(jìn)行基準(zhǔn)測試
要運(yùn)行基準(zhǔn)測試,可以使用 go test 命令,指定 -bench 標(biāo)志來啟動基準(zhǔn)測試。
go test -bench .
- bench .:表示運(yùn)行當(dāng)前目錄下所有以 Benchmark 開頭的函數(shù)。
- bench <pattern> :可以通過提供正則表達(dá)式來運(yùn)行特定的基準(zhǔn)測試,比如 go test -bench BenchmarkMyFunction 僅運(yùn)行 BenchmarkMyFunction。
運(yùn)行基準(zhǔn)測試并報告內(nèi)存分配
go test -bench . -benchmem
- benchmem:該標(biāo)志會顯示內(nèi)存分配的詳細(xì)信息,包括每次基準(zhǔn)測試中分配了多少內(nèi)存。
package mainimport ("testing""unsafe"
)func BenchmarkBytes2Str(b *testing.B) {aa := []byte("mclink")for n := 0; n < b.N; n++ {Bytes2Str(aa)}
}
func BenchmarkBytes2StrUnsafe(b *testing.B) {aa := []byte("mclink")for n := 0; n < b.N; n++ {Bytes2StrUnsafe(aa)}
}func Bytes2Str(b []byte) string {return string(b)
}func Bytes2StrUnsafe(b []byte) string {return *(*string)(unsafe.Pointer(&b))
}
#從左到右分別表示benchmark函數(shù)、運(yùn)行次數(shù)、單次運(yùn)行消耗的時間、單次運(yùn)行內(nèi)存分配的字節(jié)數(shù)和次數(shù)
BenchmarkBytes2Str-8 :基準(zhǔn)測試的名稱和 CPU 核心數(shù)量(這里 -8 表示在 8 核 CPU 上運(yùn)行)。
317858601:測試函數(shù)執(zhí)行了 20,000,000 次。
3.720 ns/op:每次執(zhí)行 BenchmarkBytes2Str-8 的平均耗時為 3.72 納秒。
0 B/op:每次測試沒有內(nèi)存分配。
0 allocs/op:每次測試沒有進(jìn)行內(nèi)存分配。
三、復(fù)雜的基準(zhǔn)測試
有時在基準(zhǔn)測試中,某些初始化工作并不應(yīng)該計(jì)入測試時間??梢允褂?b.StartTimer() 和 b.StopTimer() 來控制計(jì)時開始和結(jié)束。
func BenchmarkWithStartStopTimer(b *testing.B) {// 1. 先進(jìn)行一些初始化工作setup()// 2. 在基準(zhǔn)測試前停止計(jì)時(這部分不會計(jì)入基準(zhǔn)測試時間)b.StopTimer()// 3. 進(jìn)行某些準(zhǔn)備工作或其他代碼,這部分不會計(jì)入基準(zhǔn)測試時間time.Sleep(100 * time.Millisecond)// 4. 啟動計(jì)時,開始計(jì)入基準(zhǔn)測試時間b.StartTimer()// 5. 開始基準(zhǔn)測試for i := 0; i < b.N; i++ {performWork()}// 6. 結(jié)束時停止計(jì)時b.StopTimer()
}
- b.StartTimer():開始計(jì)時。
- b.StopTimer():停止計(jì)時。
- b.ResetTimer():重置計(jì)時器,確保計(jì)時僅限于你關(guān)心的代碼
你可以使用 b.ReportAllocs() 啟用內(nèi)存報告,來查看每次基準(zhǔn)測試中分配了多少內(nèi)存。
func BenchmarkAllocations(b *testing.B) {b.ReportAllocs() // 啟用內(nèi)存分配報告for i := 0; i < b.N; i++ {_ = make([]byte, 1024) // 模擬內(nèi)存分配}
}
- 通過 -benchtime 設(shè)置基準(zhǔn)測試時間
go test 命令支持 -benchtime 標(biāo)志,可以控制基準(zhǔn)測試的執(zhí)行時長。例如,如果你想要讓基準(zhǔn)測試執(zhí)行 2 秒鐘:
go test -bench . -benchtime=2s
- 跳過普通單元測試,只運(yùn)行基準(zhǔn)測試
如果你只想運(yùn)行基準(zhǔn)測試,而跳過普通的單元測試,可以使用 -run=^$ 來過濾單元測試:
go test -bench . -run=^$
- 和pprof 混合雙打
package mainimport ("fmt""testing""time""runtime/pprof""os"
)// 需要進(jìn)行基準(zhǔn)測試的函數(shù)
func performTask() {// 模擬耗時操作time.Sleep(100 * time.Millisecond)
}// 基準(zhǔn)測試函數(shù)
func BenchmarkWithPprof(b *testing.B) {// 創(chuàng)建一個文件來保存 CPU 分析數(shù)據(jù)f, err := os.Create("cpu.pprof")if err != nil {b.Fatal("could not create CPU profile: ", err)}defer f.Close()// 啟動 pprof,開始記錄 CPU 使用情況if err := pprof.StartCPUProfile(f); err != nil {b.Fatal("could not start CPU profile: ", err)}defer pprof.StopCPUProfile()// 進(jìn)行基準(zhǔn)測試for i := 0; i < b.N; i++ {performTask()}
}// 運(yùn)行基準(zhǔn)測試的命令:go test -bench .
// 運(yùn)行完之后會生成一個 cpu.pprof 文件,可以用 go tool pprof 查看分析數(shù)據(jù)。
如何使用 pprof 請看上一篇文章。
下一篇:Go的 Trace 工具~