Go 语言入门很简单:基准测试

举报
宇宙之一粟 发表于 2022/02/15 21:49:37 2022/02/15
【摘要】 Go 测试包包含一个基准测试工具,用于检查我们的 Go 代码的性能。 在本文中,我们将使用基准工具来逐步提高一段代码的性能。 然后,我们将讨论先进的基准测试技术,以确保我们测量的是正确的东西。Go 内置的 testing 测试框架提供了基准测试(benchmark)的能力,能让我们很容易地对某一段代码进行性能测试。什么是基准测试基准测试,是一种测试代码性能的方法,比如你有多种不同的方案,都可...

Go 测试包包含一个基准测试工具,用于检查我们的 Go 代码的性能。 在本文中,我们将使用基准工具来逐步提高一段代码的性能。 然后,我们将讨论先进的基准测试技术,以确保我们测量的是正确的东西。


Go 内置的 testing 测试框架提供了基准测试(benchmark)的能力,能让我们很容易地对某一段代码进行性能测试。


什么是基准测试

基准测试,是一种测试代码性能的方法,比如你有多种不同的方案,都可以解决问题,那么到底是那种方案性能更好呢?这时候基准测试就派上用场了。


基准测试主要是通过测试CPU和内存的效率问题,来评估被测试代码的性能,进而找到更好的解决方案。比如链接池的数量不是越多越好,那么哪个值才是最优值呢,这就需要配合基准测试不断调优了。


一个简单的基准测试

利用 Go 语言支持 benchmark 的 testing 库,接下来看一个简单的斐波那契数列的例子,斐波那契数列如下:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...


该数列的特性就是:前两个之后的每个数字都是前两个的总和。


因为该数列是递归定义的,所以计算第 n 个斐波那契数的函数经常要用到递归。定义声明如下的代码 fib.go


package fibonacci

func fib(n int) int {

	if n <= 0 {
		return 0
	} else if n == 1 {
		return 1
	}
	return fib(n-1) + fib(n-2)
}

然后我们写一个简单的测试文件 fib_test.go :

// fib_test.go
package fibonacci

import "testing"

func TestFib(t *testing.T) {
	cases := []struct {
		n    int
		want int
	}{
		{-1, 0},
		{0, 0},
		{1, 1},
		{2, 1},
		{3, 2},
		{6, 8},
		{10, 55},
	}

	for _, tt := range cases {
		got := fib(tt.n)
		if got != tt.want {
			t.Errorf("fib(%d) = %d, want %d", tt.n, got, tt.want)
		}
	}
}


$ go test -v       
=== RUN   TestFib
--- PASS: TestFib (0.00s)
PASS
ok      fib.go  1.379s

现在,这个递归斐波那契函数有效,但我们可以做得更好。 好多少? 在我们重写这个函数之前,让我们建立一个基线,我们可以比较我们未来的效率改进。 Go 提供了一个基准测试工具作为测试包的一部分。 类似于 TestX(t *testing.T),基准是用 BenchmarkX(b *testing.B) 创建的,我们创建一个 fib_bench_test.go 文件:

package fibonacci

import "testing"

func BenchmarkFib(b *testing.B) {
	// 运行 fib 函数 30 次
	for n := 0; n < b.N; n++ {
		fib(30)
	}
}


  • benchmark 和普通的单元测试用例一样,都位于 _test.go 文件中。

  • 函数名以 Benchmark 开头,参数是 b *testing.B。和普通的单元测试用例很像,单元测试函数名以 Test 开头,参数是 t *testing.T

在终端中运行 go test -bench=. 命令,上述基准测试的输出如下所示::

$ go test -bench=.
goos: windows
goarch: amd64
pkg: fib.go
cpu: Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz
BenchmarkFib-8               217           6472050 ns/op
PASS
ok      fib.go  2.395s

基准函数必须运行目标代码 b.N 次。 在基准执行期间,调整 b.N 直到基准函数持续足够长的时间以可靠地计时。


要运行基准测试,我们需要明确指示 go test 使用 -bench 标志运行基准测试。


  • -run 命令行参数类似,-bench 也接受一个正则表达式来匹配我们想要运行的基准函数。 例如,go test -bench='Fib$'

  • 要运行所有的基准测试函数,我们可以简单地提供 -bench=.. go test 将首先运行所有的测试(或者与 -run 匹配的那些,如果提供的话),然后运行基准测试。


输出告诉我们基准测试是在 windows amd64 环境中运行的。 此外,测试包执行了我们的一个基准,BenchmarkFib。 它运行 b.N 循环 217 次,每次迭代(即每次调用 fib)平均持续 6472050 ns。 这个速度属于是有点慢的,现在让我们来优化一下我们的斐波那契函数。


改进斐波那契函数重新测试

我们现在不使用递归方法的计算斐波那契数列,使用迭代的方式,代码如下:


package main

func improvedFib(n int) int {
	a, b := 0, 1
	for i := 0; i < n; i++ {
		a, b = b, a+b
	}
	return a
}

基准测试代码:

package main

import "testing"

func BenchmarkimprovedFib(b *testing.B) {
	// 运行 fib 函数 30 次
	for n := 0; n < b.N; n++ {
		improvedFib(30)
	}
}


我们再次运行 go test -bench=.。这次我们将看到两个基准测试的输出:


$ go test -bench=.
PASS
ok      fib.go/improvedFib      0.478s


参考资料:

  1. benchmark 基准测试

  2. Production Go

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。