乔克视界 乔克视界
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档

乔克

云原生爱好者
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档
  • Docker

  • Golang

    • Golang基础知识

      • 开发环境搭建
      • 常量与变量
      • 基本数据类型
      • 复合数据类型
      • 流程控制
      • 运算符
      • 位运算符详解
      • 指针
      • map
      • 函数
      • defer
      • 类型别名与自定义类型
      • 结构体
      • 接口
      • 包
      • 文件操作
      • 反射
      • 并发
      • socket网络编程
      • HTTP网络编程
      • 单元测试
      • 基准测试
        • 函数格式
        • 测试示例
        • 性能比较函数
      • 并发测试
      • 示例函数
      • 性能优化
      • go module
      • 在Go中使用Makefile
      • 部署Go项目
    • Golang进阶知识

    • Golang常用包

  • AIOps

  • 专栏
  • Golang
  • Golang基础知识
乔克
2025-07-13
目录

基准测试

# 函数格式

基准测试就是在一定的工作负载之下检测程序性能的一种方法。基准测试的基本格式如下:

func BenchmarkName(b *testing.B){
    // ...
}
1
2
3

基准测试以Benchmark为前缀,需要一个*testing.B类型的参数 b,基准测试必须要执行b.N次,这样的测试才有对照性,b.N的值是系统根据实际情况去调整的,从而保证测试的稳定性。 testing.B拥有的方法如下:

func (c *B) Error(args ...interface{})
func (c *B) Errorf(format string, args ...interface{})
func (c *B) Fail()
func (c *B) FailNow()
func (c *B) Failed() bool
func (c *B) Fatal(args ...interface{})
func (c *B) Fatalf(format string, args ...interface{})
func (c *B) Log(args ...interface{})
func (c *B) Logf(format string, args ...interface{})
func (c *B) Name() string
func (b *B) ReportAllocs()
func (b *B) ResetTimer()
func (b *B) Run(name string, f func(b *B)) bool
func (b *B) RunParallel(body func(*PB))
func (b *B) SetBytes(n int64)
func (b *B) SetParallelism(p int)
func (c *B) Skip(args ...interface{})
func (c *B) SkipNow()
func (c *B) Skipf(format string, args ...interface{})
func (c *B) Skipped() bool
func (b *B) StartTimer()
func (b *B) StopTimer()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 测试示例

func BenchmarkSplit(b *testing.B) {
	for i := 0; i < b.N; i++ {
		SplitStr("a:b:c:d", ":")
	}
}
1
2
3
4
5

然后运行测试用例:

使用代码go test -bench=Split:

PS E:\DEV\Go\src\code.rookieops.com\day05\splitStr> go test -bench=Split
goos: windows
goarch: amd64
pkg: code.rookieops.com/day05/splitStr
BenchmarkSplit-4         2999503               409 ns/op
PASS
ok      code.rookieops.com/day05/splitStr       3.633s
1
2
3
4
5
6
7

其中BenchmarkSplit-4表示对 Split 函数进行基准测试,数字4表示GOMAXPROCS的值,这个对于并发基准测试很重要。2999503和 409ns/op表示每次调用Split函数耗时409ns,这个结果是2999503次调用的平均值。

我们还可以为基准测试添加`-benchmem`参数,来获得内存分配的统计数据。
go test -bench=Split -benchmem
goos: windows
goarch: amd64
pkg: code.rookieops.com/day05/splitStr
BenchmarkSplit-4         3591652               311 ns/op             112 B/op          3 allocs/op
PASS
ok      code.rookieops.com/day05/splitStr       2.219s
1
2
3
4
5
6
7

其中,112 B/op表示每次操作内存分配了 112 字节,3 allocs/op则表示每次操作进行了 3 次内存分配。

我们将我们的Split函数优化如下:

package splitStr

import "strings"

// SplitStr ..
func SplitStr(s, sep string) (res []string) {
	// 取索引
	res = make([]string, 0, strings.Count(s, sep)+1)
	index := strings.Index(s, sep)
	for index >= 0 {
		res = append(res, s[:index])
		s = s[index+len(sep):]
		index = strings.Index(s, sep)
	}
	res = append(res, s)
	return
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

然后运行测试代码如下:

 go test -bench=Split -benchmem
goos: windows
goarch: amd64
pkg: code.rookieops.com/day05/splitStr
BenchmarkSplit-4         4508462               233 ns/op              64 B/op          1 allocs/op
PASS
ok      code.rookieops.com/day05/splitStr       3.234s
1
2
3
4
5
6
7

这一次我们提前使用 make 函数将 res 初始化为一个容量足够大的切片,而不再像之前一样通过调用 append 函数来追加。这样以来减少了 2/3 的内存分配次数,并且减少了一半的内存分配。

# 性能比较函数

性能比较函数是对一个函数处理不同请求的差别。

如下编写一个斐波拉契函数:

// Fib 斐波拉契函数
func Fib(n int) int {
	if n < 2 {
		return n
	}
	return Fib(n-1) + Fib(n-2)
}
1
2
3
4
5
6
7

然后我们编写性能比较函数:

func benchmarkFib(b *testing.B, n int) {
	for i := 0; i < b.N; i++ {
		Fib(n)
	}
}

func BenchmarkFib1(b *testing.B) {
	benchmarkFib(b, 1)
}

func BenchmarkFib2(b *testing.B) {
	benchmarkFib(b, 2)
}

func BenchmarkFib3(b *testing.B) {
	benchmarkFib(b, 3)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

运行测试用例代码如下:

PS E:\DEV\Go\src\code.rookieops.com\day05\splitStr> go test -bench=Fib1
goos: windows
goarch: amd64
pkg: code.rookieops.com/day05/splitStr
BenchmarkFib1-4         278520369                4.16 ns/op
PASS
ok      code.rookieops.com/day05/splitStr       2.819s
PS E:\DEV\Go\src\code.rookieops.com\day05\splitStr> go test -bench=Fib2
goos: windows
goarch: amd64
pkg: code.rookieops.com/day05/splitStr
BenchmarkFib2-4         128817837                8.50 ns/op
PASS
ok      code.rookieops.com/day05/splitStr       2.764s
PS E:\DEV\Go\src\code.rookieops.com\day05\splitStr> go test -bench=Fib3
goos: windows
goarch: amd64
pkg: code.rookieops.com/day05/splitStr
BenchmarkFib3-4         80003732                16.0 ns/op
PASS
ok      code.rookieops.com/day05/splitStr       2.283s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

需要注意的是,默认情况下,每个基准测试至少运行 1 秒。如果在 Benchmark 函数返回时没有到 1 秒,则 b.N 的值会按 1,2,5,10,20,50,…增加,并且函数再次运行。

上次更新: 2025/07/18, 11:04:43
单元测试
并发测试

← 单元测试 并发测试→

最近更新
01
2025年,SRE在企业中可以做哪些事
07-18
02
SRE 如何提升自己在团队中的影响力
07-18
03
使用Go开发MCP服务
07-18
更多文章>
Theme by Vdoing | Copyright © 2019-2025 乔克 | MIT License | 渝ICP备20002153号 |
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式