引入
测试验证功能正确,但性能呢?Go 的 testing 包自带基准测试,用 Benchmark 函数测量代码执行耗时,找出性能瓶颈,不用装额外工具。
正文
定义
定义
基准测试(benchmark)用来测量代码执行性能。测试函数以
Benchmark开头,签名为func BenchmarkXxx(b *testing.B),框架自动调整b.N的迭代次数直到结果稳定。
语法
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(1, 2)
}
}例子
基本基准测试
func BenchmarkFmtSprint(b *testing.B) {
for i := 0; i < b.N; i++ {
fmt.Sprint("hello")
}
}运行 go test -bench=. 后,框架自动确定 b.N 的大小,输出每次操作的平均耗时。
带初始化的基准测试
func BenchmarkSort(b *testing.B) {
data := make([]int, 1000)
b.ResetTimer()
for i := 0; i < b.N; i++ {
sort.Ints(data)
}
}b.ResetTimer() 清掉初始化耗时,只测目标代码的性能。
子基准测试
func BenchmarkSort(b *testing.B) {
sizes := []int{10, 100, 1000}
for _, size := range sizes {
b.Run(fmt.Sprintf("size=%d", size), func(b *testing.B) {
data := make([]int, size)
for i := range data {
data[i] = size - i
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
sort.Ints(data)
}
})
}
}子基准测试用 b.Run() 分组,能直观对比不同输入规模下的性能差异。
内存分配统计
func BenchmarkAlloc(b *testing.B) {
for i := 0; i < b.N; i++ {
s := make([]byte, 1024)
_ = s
}
}加 -benchmem 参数输出每次操作的内存分配次数和字节数。
常见写法
| 写法 | 说明 |
|---|---|
go test -bench=. | 运行所有基准测试 |
go test -bench=Name | 运行指定基准测试 |
go test -benchmem | 显示内存分配 |
go test -bench=. -count=3 | 重复运行 3 次 |
b.ResetTimer() | 重置计时器(忽略初始化耗时) |
b.StopTimer() | 暂停计时 |
b.StartTimer() | 恢复计时 |
b.ReportAllocs() | 输出内存分配统计 |
b.Run(name, fn) | 创建子基准测试 |
特点
- 基准测试函数必须以
Benchmark开头,参数是*testing.B b.N由框架自动调整,不需要手动设定- 循环体必须用
for i := 0; i < b.N; i++包裹目标代码 b.ResetTimer()用来排除初始化开销- 结果单位是 ns/op(纳秒每次操作),越小越好
- 加
-benchmem能看到 allocs/op 和 B/op - 同一测试跑多次(
-count)能减少偶然误差
理解
基准测试就是给代码跑个分。b.N 自动调大小,测出来的 ns/op 稳定可靠。配合 b.ResetTimer() 排除干扰,-benchmem 看内存分配,基本能定位大部分性能问题。不用写专门的压测工具,go test 一条命令全搞定。
引出
基准测试发现了性能瓶颈,接下来怎么构建、检查和格式化代码?看 Go 工具链,了解 Go 自带的开发工具全家桶。