Go語言基準測試(benchmark)三部曲之一:基礎篇

歡迎訪問我的GitHub

這裏分類和彙總了欣宸的全部原創(含配套源碼):https://github.com/zq2599/blog_demos

關於基準測試(benchmark)

  • Go的標準庫內置的testing框架提供了基準測試(benchmark)功能,可以用來驗證本地方法在串行或者並行執行時的基準表現,幫助開發者瞭解代碼的真實性能情況,例如一個方法執行一次的平均耗時,還能看到內存分配的情況

關於Go語言基準測試(benchmark)三部曲

  • 《Go語言基準測試(benchmark)三部曲》是欣宸的優異又一些列原創,旨在通過簡單的編碼實戰與大家一同學習和鞏固基準測試的常見操作,共分爲:基礎篇、內存篇、提高篇三部分,每篇都目標明確,用少量代碼和命令快速熟悉對應知識點,相信《三部曲》結束後,您也能輕鬆完成基準測試,根高效的檢查代碼性能

本篇概覽

  • 作爲系列的開篇,本文的目標是和大家一起快速開始基準測試,然後將常用的參數和命令都用上一遍,具體步驟如下
  1. 編碼,寫個本地方法,後面就用benchmark來驗證這些方法的性能
  2. 最基本的基準測試
  3. 匹配規則
  4. -cpu參數
  5. -benchtime參數
  6. -count參數
  7. 並行測試

環境信息

  • 操作系統:Windows 11 家庭中文版(22H2),12代i5處理器,16G內存
  • Go:1.19.3
  • VSCode:1.75.1

編碼

  • benchmark是用來對已有方法做測試的,因此一開始要把被測試的方法準備好,然後像單元測試那樣編寫benchmark測試代碼,最後用go test做基準測試,咱們這就動手把方法準備好
  • 準備一個目錄,名爲benchmark-demo,在目錄下執行以下命令,新建一個module
go mod init benchmark-demo
  • 用vscode打開此目錄,會識別到module,接下來可以在vscode中操作了
  • 新建文件benchmark-demo,裏面是用來做基準測試的方法,先寫一個簡單的方法fib
package main

// 斐波拉契數列
func fib(n int) int {
	if n == 0 || n == 1 {
		return n
	}

	return fib(n-2) + fib(n-1)
}
  • 接下來就用benchmark來測試fib方法,看看其性能情況

最基本的基準測試

  • 最基本的基準測試是從兩個維度去檢測方法的性能
  1. 指定時間內,檢查方法的運行的耗時
  2. 指定次數,檢查方法的運行的耗時
  • 具體操作分爲兩部
  1. 寫benchmark測試方法,就像寫單元測試代碼一樣,代碼位於_test.go結尾的文件中
  2. 執行benchmark測試
  • 先來寫benchmakr測試方法,新建名爲main_test.go,裏面有個方法BenchmarkFib,注意要以Benchmark開始,入參是*testing.B類型,這就是最簡單的benchmark方法了
func BenchmarkFib(b *testing.B) {
	for n := 0; n < b.N; n++ {
		fib(30)
	}
}
  • 現在用命令行進行測試,執行下面這個最精簡的命令,注意:要執行benchmark測試就要帶-bench
go test -bench .
  • 很快就完成了基準測試,控制檯輸出如下,具體含義稍後解釋
goos: windows
goarch: amd64
pkg: benchmark-demo
cpu: 12th Gen Intel(R) Core(TM) i5-1240P
BenchmarkFib-16              322           3653937 ns/op
PASS
ok      benchmark-demo  1.999s
  • 最前面幾行是基本信息, 整理如下
名稱 含義
goos 操作系統,這裏是windows
goarch CPU架構,這裏是64位X86
pkg package名,可以在測試的時候指定package
cpu CPU的信息,這裏可以看到是12代酷睿i5
  • 接下來是benchmark的結果,每個數字的具體解釋如下圖所示
    在這裏插入圖片描述
  • benchmark也可以像普通單元測試那樣添加驗證邏輯的代碼,測試結果可以是通過和不通過,BenchmarkFib中沒有像普通單元測試那樣的失敗邏輯,因此最終的判斷是測試通過,控制檯中輸出了PASS
  • 將同樣的測試在M1 Pro芯片的Mac Book Pro上運行一遍試試,獲取結果如下,可見和前面的windows測試結果大致相近,不同的是結果中沒有CPU信息
go test -bench .
goos: darwin
goarch: arm64
pkg: benchmark-demo
BenchmarkFib-8   	     326	   3647077 ns/op
PASS
ok  	benchmark-demo	1.654s
  • 以上就是最基礎的benchmark測試了,咱們已經驗證了,接下來試試那些常用的參數

匹配規則

  • 在有多個Benchmark測試方法的時候,如何做到只運行指定的方法呢?
  • 先看指定package的
  1. 指定package:go test -bench benchmark-demo
  2. 指定子package:go test -bench benchmark-demo/XXX
  3. 當前目錄下的所有package:go test -bench ./... (斜槓左側是一個點,右側是三個點)
  • 再看指定方法的,可以用正則表達式來指定方法名
  1. 所有以Fib結尾的方法:go test -bench='Fib$' benchmark-demo
  2. 所有以BenchmarkNew開始的方法:go test -bench='^BenchmarkNew' benchmark-demo
  • 接下來看幾個常用參數

-cpu參數

  • 前面的測試結果BenchmarkFib-16可以看出測試中的GOMAXPROCS等於16,這個值可以用-cpu參數來調整,不過咱們這裏不涉及併發編程,GOMAXPROCS的變化對測試結果沒有影響,改一下試試,果然沒啥波動(稍後還會講到並行測試,那時候cpu參數的作用就非常明顯了)
go test -bench='Fib$' -cpu=2 .  
goos: windows
goarch: amd64
pkg: benchmark-demo
cpu: 12th Gen Intel(R) Core(TM) i5-1240P
BenchmarkFib-2               320           3692123 ns/op
PASS
ok      benchmark-demo  1.962s

-benchtime參數

  • 前面的命令中我們並沒有指定測試時長,因此使用的是默認值1秒,現在咱們來修改這個參數試試,畢竟1秒內完成基準測試並不是普遍適用的
  • 指定基準測試時長爲10秒:go test -bench='Fib$' -benchtime=10s benchmark-demo
  • 結果如下
goos: windows
goarch: amd64
pkg: benchmark-demo
cpu: 12th Gen Intel(R) Core(TM) i5-1240P
BenchmarkFib-16             3264           3668947 ns/op
PASS
ok      benchmark-demo  12.710s
  • 除了指定時間,還能指定次數,就是指定下圖黃色箭頭所指的值,也就是控制了被測試方法所執行的次數
    在這裏插入圖片描述
  • 指定每輪基準測試內的循環次數爲999次:go test -bench='Fib$' -benchtime=999x benchmark-demo
  • 注意將-benchtime的值從10s改爲999x,測試範圍就從時間變成了次數,測試結果如下,可見準確的執行了999次
go test -bench='Fib$' -benchtime=999x benchmark-demo
goos: windows
goarch: amd64
pkg: benchmark-demo
cpu: 12th Gen Intel(R) Core(TM) i5-1240P
BenchmarkFib-16              999           3667776 ns/op
PASS
ok      benchmark-demo  4.006s

-count參數

  • count參數也是用來控制執行次數的,和前面提到的benchtime不同,count用來控制BenchmarkXXX方法的調用次數,而benchtime是用來控制BenchmarkXXX方法的入參b.N的值,如下圖所示
    在這裏插入圖片描述
  • 指定每輪基準測試內的循環次數爲999次,一共兩輪:go test -bench='Fib$' -benchtime=999x -count=2 benchmark-demo,輸出如下,還是很容易理解的
go test -bench='Fib$' -benchtime=999x -count=2 benchmark-demo
goos: windows
goarch: amd64
pkg: benchmark-demo
cpu: 12th Gen Intel(R) Core(TM) i5-1240P
BenchmarkFib-16              999           3656639 ns/op
BenchmarkFib-16              999           3645846 ns/op
PASS
ok      benchmark-demo  7.709s

並行測試

  • 前面的BenchmarkFib是常規的串行測試,如果被測試的方法在真實環境中存在併發調用,那麼在基準測試中也應該通過並行測試來了解其基本性能(例如鎖造成的阻塞)
  • 爲了對fib方法做並行基準測試,需要編寫對應的基準測試代碼,如下
func BenchmarkParallelFib(b *testing.B) {
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			fib(30)
		}
	})
}
  • 執行go test -bench='^Benchmark' benchmark-demo,這時BenchmarkFibBenchmarkParallelFib都會執行,測試結果如下,可見相同時間內,執行fib的總次數是隨着併發數量而增加
go test -bench='^Benchmark' benchmark-demo       
goos: windows
goarch: amd64
pkg: benchmark-demo
cpu: 12th Gen Intel(R) Core(TM) i5-1240P
BenchmarkFib-16                      368           3362756 ns/op
BenchmarkParallelFib-16             3134            370352 ns/op
PASS
ok      benchmark-demo  3.189s
  • 通過cpu參數指定GOMAXPROCS數量,執行命令go test -bench='^Benchmark' -cpu=8 benchmark-demo,結果如下,可見串行方法的測試結果沒有變化,而並行測試的結果隨着GOMAXPROCS的減少有明顯下降
go test -bench='^Benchmark' -cpu=8 benchmark-demo
goos: windows
goarch: amd64
pkg: benchmark-demo
cpu: 12th Gen Intel(R) Core(TM) i5-1240P
BenchmarkFib-8                       356           3352500 ns/op
BenchmarkParallelFib-8              1989            582177 ns/op
PASS
ok      benchmark-demo  3.211s
  • 最後注意,除了cpu參數,前面用過的benchtime和count也都適用於並行測試,含義和串行測試的場景一致
  • 至此,最基本的基準測試已經完成了,下一篇咱們會進行內存相關的基準測試,觀察內存的使用和分配情況,敬請期待

歡迎關注博客園:程序員欣宸

學習路上,你不孤單,欣宸原創一路相伴...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章