如何在 Go 語言內寫效能測試

golang logo

Go 語言不只有內建基本的 Testing 功能,另外也內建了 Benchmark 工具,讓開發者可以快速的驗證自己寫的程式碼效能如何?該如何使用基本的 Benchmark 工具,底下用簡單的例子來說明如何寫 Benchmark,透過內建工具可以知道程式碼單次執行多少時間,以及用了多少記憶體。不多說直接用『數字轉字串』來當例子。

線上影片

如果您不想看底下的文字說明,可以直接參考線上影片教學:

另外我在 Udemy 上面開了兩門課程,一門 drone 另一門 golang 教學,如果對這兩門課有興趣的話,都可以購買,目前都是特價 $1800

如果兩們都有興趣想一起合買,請直接匯款到下面帳戶,特價 $3000

  • 富邦銀行: 012
  • 富邦帳號: 746168268370
  • 匯款金額: 台幣 $3000 元

如何寫 Benchmark

建立 main_test.go 檔案

1
2
3
4
5
func BenchmarkPrintInt2String01(b *testing.B) {
    for i := 0; i < b.N; i++ {
        printInt2String01(100)
    }
}
  • 檔案名稱一定要用 _test.go 當結尾
  • func 名稱開頭要用 Benchmark
  • for 循環內要放置要測試的程式碼
  • b.N 是 go 語言內建提供的循環,根據一秒鐘的時間計算
  • 跟測試不同的是帶入 b *testing.B 參數

底下是測試指令:

1
2
3
4
5
$ go test -v -bench=. -run=none .
goos: darwin
goarch: amd64
BenchmarkPrintInt2String01-4    10000000               140 ns/op
PASS

基本的 benchmark 測試也是透過 go test 指令,不同的是要加上 -bench=.,這樣才會跑 benchmark 部分,否則預設只有跑測試程式,大家可以看到 -4 代表目前的 CPU 核心數,也就是 GOMAXPROCS 的值,另外 -run 可以用在跑特定的測試函示,但是假設沒有指定 -run 時,你會看到預設跑測試 + benchmark,所以這邊補上 -run=none 的用意是不要跑任何測試,只有跑 benchmark,最後看看輸出結果,其中 10000000 代表一秒鐘可以跑 1000 萬次,每一次需要 140 ns,如果你想跑兩秒,請加上此參數在命令列 -benchtime=2s,但是個人覺得沒什麼意義。

效能比較

底下直接看看『數字轉字串』效能評估,參考底下寫出三種數字轉字串函式,線上程式碼

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
func printInt2String01(num int) string {
    return fmt.Sprintf("%d", num)
}

func printInt2String02(num int64) string {
    return strconv.FormatInt(num, 10)
}
func printInt2String03(num int) string {
    return strconv.Itoa(num)
}

接著寫 benchmark,線上程式碼

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
func BenchmarkPrintInt2String01(b *testing.B) {
    for i := 0; i < b.N; i++ {
        printInt2String01(100)
    }
}

func BenchmarkPrintInt2String02(b *testing.B) {
    for i := 0; i < b.N; i++ {
        printInt2String02(int64(100))
    }
}

func BenchmarkPrintInt2String03(b *testing.B) {
    for i := 0; i < b.N; i++ {
        printInt2String03(100)
    }
}

跑測試

1
2
3
4
5
6
7
8
$ go test -v -bench=. -run=none -benchmem .
goos: darwin
goarch: amd64
BenchmarkPrintInt2String01-4    10000000               125 ns/op              16 B/op          2 allocs/op
BenchmarkPrintInt2String02-4    30000000                37.8 ns/op             3 B/op          1 allocs/op
BenchmarkPrintInt2String03-4    30000000                38.6 ns/op             3 B/op          1 allocs/op
PASS
ok      _/Users/mtk10671/git/go/src/github.com/go-training/training/example20-write-benchmark   3.800s

可以很清楚看到使用 strconv.FormatInt 效能是最好的。透過 -benchmem 可以清楚知道記憶體分配方式,用此方式就可以知道要優化哪些函示。1 allocs/op 代表每次執行都需要搭配一個記憶體空間,而一個記憶體空間為 3 Bytes


See also