Go语言学习笔记(1)--- 基准测试

go 刘宇帅 5年前 阅读量: 1181

什么是基准测试

基准测试是测量一个程序在固定工作负载下的性能。我们通常会用来对比对同一个问题不同解决方案的性能,从而帮助我们做决定选择哪个方案更合理。

Go 的基准测试

Go 基准测试规则如下:

  • 必须放在以 _test.go 结尾的文件中。
  • 函数名必须以 Benchmark 开头
  • 函数必须接受一个参数 *testing.B
  • 没有返回值

基准测试受机器状态等因素的影响每次跑的结果很难保持完全一致,但是基本会在一个很小的范围内波动。
写一个简单的基准测试如下

import "testing"

func sum() int {
    sum := 0
    for i := 1; i <= 100; i++ {
        sum += i
    }
    return sum
}

func BenchmarkTest(b *testing.B) {
    for i := 0; i < b.N; i++ {
        sum()
    }
}

运行结果如下

> $ go test -bench=Sum -run=^1
goos: darwin
goarch: amd64
pkg: github.com/yushuailiu/easyGolang/benchmark
BenchmarkSum-4      20000000            60.8 ns/op
PASS
ok      github.com/yushuailiu/easyGolang/benchmark  1.287s

跑基准测试仍然使用 go test 命令,但是需要添加 -bench= 参数来标识跑基准测试,-bench 参数值跟一个正则表达式表示需要跑的基准测试,我们可以用 . 表示跑所有的,如果我们基准测试比较多可以使用正则指明,比如上面的我们只需要跑 Sum。-run=^1 是为了禁止跑单元测试,因为 go test 默认会在跑基准测试前跑单元测试,我们这里为了单纯的跑基准测试,所以需要禁止单元测试,而 -run=^1 用来指明需要跑的单元测试的正则,很显然没有以 1 开头的的单元测试,所有该参数的意思是禁止跑单元测试。
输出结果我们可以看到 BenchmarkSum-4,这里是 4 是指运行时的 GOMAXPROC 的值。 20000000 表示 t.N 的值,即我们跑了 20000000 次 sum(),60.8 表示跑一次需要 60.8 纳秒。
基准测试参数-benchtime= 用来指定基准测试的时间,默认基准测试是跑1s,有时候性能相当的两个程序可以通过增加压测时间对比差别,但是最长不要超过3s,因为如果算法是稳定的时间再长是没有意义的。
基准测试参数-benchmem用来显示每次操作内存分配的次数,以及每次操作分配的字节数,可以用来对比不同程序的性能根源,因为很显然内存操作多,分配字节多的自然会需要更多地时间。

基准测试的具体使用

我前面有写了一篇关于冒泡排序算法的实现,里面有提到 3 种实现,我们这里对 3 种实现做基准测试比较 3 种实现的性能。基准测试代码源码地址 算法地址

import "testing"

var list = []map[string][]int{
    {
        "origin": {10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
        "result": {1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
    },
    {
        "origin": {22, 33, 22, 1, 2, 11, 22, 123, 110},
        "result": {1, 2, 11, 22, 22, 22, 33, 110, 123},
    },
    {
        "origin": {22, 23, 10, 9, 54, 17, 100, 2},
        "result": {2, 9, 10, 17, 22, 23, 54, 100},
    },
    {
        "origin": {22, 23, 22, 23, 22, 23, 22, 23},
        "result": {22, 22, 22, 22, 23, 23, 23, 23},
    },
    {
        "origin": {1, 1111, 298989, 8422, 2222, 44422},
        "result": {1, 1111, 2222, 8422, 44422, 298989},
    },
    {
        "origin": {22, 10, 1, 99, 22, 10, 11, 10, 2, 100},
        "result": {1, 2, 10, 10, 10, 11, 22, 22, 99, 100},
    },
    {
        "origin": {23, 22},
        "result": {22, 23},
    },
    {
        "origin": {1},
        "result": {1},
    },
    {
        "origin": {},
        "result": {},
    },
}

func listEqual(list1, list2 []int) bool {
    for index, _ := range list1 {
        if list1[index] != list2[index] {
            return false
        }
    }
    return true
}

func BenchmarkBubbleSort1(b *testing.B) {
    for i := 0; i < b.N; i++ {
        for _, item := range list {
            origin := make([]int, len(item["origin"]))
            copy(origin, item["origin"])
            BubbleSort1(origin)
            if !listEqual(origin, item["result"]) {
                b.Error("bubble sort", item["origin"], "should be", item["result"],
                    "but get", origin)
            }
        }
    }
}
func BenchmarkBubbleSort2(b *testing.B) {
    for i := 0; i < b.N; i++ {
        for _, item := range list {
            origin := make([]int, len(item["origin"]))
            copy(origin, item["origin"])
            BubbleSort2(origin)
            if !listEqual(origin, item["result"]) {
                b.Error("bubble sort", item["origin"], "should be", item["result"],
                    "but get", origin)
            }
        }
    }
}
func BenchmarkBubbleSort3(b *testing.B) {
    for i := 0; i < b.N; i++ {
        for _, item := range list {
            origin := make([]int, len(item["origin"]))
            copy(origin, item["origin"])
            BubbleSort3(origin)
            if !listEqual(origin, item["result"]) {
                b.Error("bubble sort", item["origin"], "should be", item["result"],
                    "but get", origin)
            }
        }
    }
}

运行基准测试

> $ go test -bench=BubbleSort* -run=^1 -v
goos: darwin
goarch: amd64
pkg: github.com/yushuailiu/go-algorithm/sort
BenchmarkBubbleSort1-4       1000000          1012 ns/op
BenchmarkBubbleSort2-4       2000000           993 ns/op
BenchmarkBubbleSort3-4       2000000           883 ns/op
PASS
ok      github.com/yushuailiu/go-algorithm/sort 6.676s

可以看到 BubbleSort2 比 BubbleSort1 稍有提升,而 BubbleSort3 比 BubbleSort2 提升还是挺大的。

提示

功能待开通!


暂无评论~