1

#yyds干货盘点#Go 语言入门很简单:基准测试

 2 years ago
source link: https://blog.51cto.com/yuzhou1su/5093255
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

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

#yyds干货盘点#Go 语言入门很简单:基准测试_递归

什么是基准测试

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

基准测试主要是通过测试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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK