本文旨在深入探讨 Go 语言中 `testing.B` 性能基准测试工具的正确使用方法。针对用户在切片排序算法基准测试中遇到的异常结果,文章将详细解析 `b.N` 循环、`b.ResetTimer()` 等核心机制,并提供规范的基准测试模板及注意事项,帮助开发者避免常见误区,获取准确可靠的性能数据。
在 Go 语言中进行性能基准测试时,开发者常会遇到一些看似异常的结果,例如某些基准测试函数执行时间极短(接近 0 ns/op)且内存分配为零。这通常不是被测试代码本身的问题,而是对 testing.B 工具使用不当所致。
考虑以下用户提供的排序算法基准测试代码片段:
package child_sort
import (
"math/rand"
"testing"
"time"
)
// generate 函数用于生成随机整数切片
func generate(size int, min, max int) []int {
// 注意:在基准测试中,rand.Seed 应避免在每次调用时都用 time.Now() 重新播种
// 更好的做法是在包初始化时播种一次,或使用固定种子以保证测试可复现性。
// 这里为了示例,暂时保留用户原代码结构,但在实际应用中需注意。
rand.Seed(time.Now().UTC().UnixNano())
var xs = make([]int, size, size)
for i := range xs {
xs[i] = min + rand.Intn(max-min)
}
return xs
}
// 示例排序函数(此处省略具体实现,假设已定义 SortBubble, SortSelection, SortInsertion)
// func SortBubble(xs []int) { /* ... */ }
// func SortSelection(xs []int) { /* ... */ }
// func SortInsertion(xs []int) { /* ... */ }
func BenchmarkBubble(b *testing.B) {
xs := generate(10000, -100, 100)
/* b.ResetTimer() */ // 注释掉的行
SortBubble(xs)
}
func BenchmarkSelection(b *testing.B) {
xs := generate(10000, -100, 100)
/* b.ResetTimer() */ // 注释掉的行
SortSelection(xs)
}
func BenchmarkInsertion(b *testing.B) {
xs := generate(10000, -100, 100)
/* b.ResetTimer() */ // 注释掉的行
SortInsertion(xs)
}当运行 go test --bench . --benchmem 时,可能出现如下异常结果:
BenchmarkSelection 1000000000 0.60 ns/op 0 B/op 0 allocs/op
这种现象的根本原因在于,基准测试函数 BenchmarkSelection 内部的 SortSelection(xs) 调用只执行了一次。go test 命令在执行基准测试时,会尝试运行 b.N 次被测试的代码以获取足够精确的统计数据。然而,如果被测试的核心逻辑没有被包含在一个 for i := 0; i
testing.B 是 Go 语言中用于性能基准测试的核心结构体,它提供了几个关键方法来帮助我们精确测量代码性能:
执行一些准备工作(如数据生成),然后调用 b.ResetTimer() 来排除这些准备工作的时间开销,确保只测量核心逻辑的性能。要正确地进行 Go 语言的性能基准测试,核心原则是将待测代码包裹在 for i := 0; i
以下是修正后的基准测试代码示例:
package child_sort
import (
"math/rand"
"testing"
"time"
)
// generate 函数:优化 rand.Seed 的使用
// 在基准测试中,通常将 rand.Source 的初始化放在基准测试函数外部,
// 或者使用一个固定种子,以确保每次基准测试运行的数据分布一致。
var globalRand *rand.Rand
func init() {
source := rand.NewSource(time.Now().UTC().UnixNano())
globalRand = rand.New(source)
}
func generate(size int, min, max int) []int {
xs := make([]int, size)
for i := range xs {
xs[i] = min + globalRand.Intn(max-min)
}
return xs
}
// 假设 SortSelection, SortBubble, SortInsertion 函数已定义
func SortBubble(xs []int) {
for i := range xs {
swapped := false
for j := 1; j < len(xs)-i; j++ {
if xs[j-1] > xs[j] {
xs[j-1], xs[j] = xs[j], xs[j-1]
swapped = true
}
}
if !swapped {
break
}
}
}
func SortSelection(xs []int) {
for i := range xs {
min_i := i
for j := i + 1; j < len(xs); j++ {
if xs[j] < xs[min_i] {
min_i = j
}
}
if min_i != i {
xs[i], xs[min_i] = xs[min_i], xs[i]
}
}
}
func SortInsertion(xs []int) {
for i := 1; i < len(xs); i++ {
for j := i; j > 0; j-- {
if xs[j] < xs[j-1] {
xs[j], xs[j-1] = xs[j-1], xs[j]
}
}
}
}
// 修正后的基准测试函数
func BenchmarkBubbleCorrect(b *testing.B) {
// 1. 准备初始的未排序切片(模板数据),只执行一次
initialXs := generate(10000, -100, 100)
b.ResetTimer() // 2. 重置计时器,排除数据准备的时间开销
// 3. 循环 b.N 次,执行待测函数
for i := 0; i < b.N; i++ {
// 4. 重要:每次迭代都需提供一份新的、未排序的数据副本
// 因为排序算法会修改原始切片,如果直接使用 initialXs,
// 后续迭代将对已排序的切片进行操作,导致结果失真。
dataToSort := make([]int, len(initialXs))
copy(dataToSort, initialXs)
SortBubble(dataToSort) // 5. 调用待测函数
}
}
func BenchmarkSelectionCorrect(b *testing.B) {
initialXs := generate(10000, -100, 100)
b.ResetTimer()
for i := 0; i < b.N; i++ {
dataToSort := make([]int, len(initialXs))
copy(dataToSort, initialXs)
SortSelection(dataToSort)
}
}
func BenchmarkInsertionCorrect(b *testing.B) {
initialXs := generate(10000, -100, 100)
b.ResetTimer()
for i := 0; i < b.N; i++ {
dataToSort := make([]int, len(initialXs))
copy(dataToSort, initialXs)
SortInsertion(dataToSort)
}
}运行修正后的基准测试:
go test --bench . --benchmem
现在,您将看到更合理且有意义的性能数据,反映了排序算法在多次执行下的平均性能。
数据准备与隔离:
避免死代码消除:
理解 go test --bench 参数:
一致性与可复现性:
Go 语言的 testing.B 提供了一个强大的工具来进行性能基准测试。然而,要获得准确可靠的性能数据,理解并正确使用 b.N 循环和 b.ResetTimer() 至关重要。通过遵循本文介绍的正确实践,特别是针对修改输入数据的函数进行数据副本处理,开发者可以有效地避免常见误区,从而对代码性能进行精确分析和优化。
# go
# 正则表达式
# app
# 字节
# 工具
# unix
# 排序算法
# for
# 结构体
# 循环
# 切片
# copy
# 算法
# 计时器
# 迭代
# 是在
# 放在
# 准备工作
# 以保证
# 测试中
# 返回值
# 都是
# 几个
相关文章:
北京网站制作网页,网站升级改版需要多久?
nginx修改上传文件大小限制的方法
在线制作视频网站免费,都有哪些好的动漫网站?
如何将凡科建站内容保存为本地文件?
如何通过虚拟主机快速完成网站搭建?
如何访问已购建站主机并解决登录问题?
车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?
如何快速搭建二级域名独立网站?
视频网站制作教程,怎么样制作优酷网的小视频?
如何在香港免费服务器上快速搭建网站?
建站IDE高效指南:快速搭建+SEO优化+自适应模板全解析
建站主机是否属于云主机类型?
,石家庄四十八中学官网?
C++ static_cast和dynamic_cast区别_C++静态转换与动态类型安全转换
如何在沈阳梯子盘古建站优化SEO排名与功能模块?
建站之星CMS建站配置指南:模板选择与SEO优化技巧
如何快速生成凡客建站的专业级图册?
如何在Windows环境下新建FTP站点并设置权限?
重庆市网站制作公司,重庆招聘网站哪个好?
无锡营销型网站制作公司,无锡网选车牌流程?
微信h5制作网站有哪些,免费微信H5页面制作工具?
如何在万网开始建站?分步指南解析
网站制作话术技巧,网站推广做的好怎么话术?
如何在建站之星网店版论坛获取技术支持?
专业的网站制作设计是什么,如何制作一个企业网站,建设网站的基本步骤有哪些?
如何零基础开发自助建站系统?完整教程解析
建站之星安装模板失败:服务器环境不兼容?
云南网站制作公司有哪些,云南最好的招聘网站是哪个?
成都品牌网站制作公司,成都营业执照年报网上怎么办理?
如何配置FTP站点权限与安全设置?
python的本地网站制作,如何创建本地站点?
如何快速启动建站代理加盟业务?
大连网站制作费用,大连新青年网站,五年四班里的视频怎样下载啊?
如何规划企业建站流程的关键步骤?
详解jQuery中基本的动画方法
建站之星Pro快速搭建教程:模板选择与功能配置指南
建站为何优先选择香港服务器?
西安大型网站制作公司,西安招聘网站最好的是哪个?
如何在Golang中指定模块版本_使用go.mod控制版本号
制作营销网站公司,淘特是干什么用的?
免费制作小说封面的网站有哪些,怎么接网站批量的封面单?
再谈Python中的字符串与字符编码(推荐)
建站主机空间推荐 高性价比配置与快速部署方案解析
网站好制作吗知乎,网站开发好学吗?有什么技巧?
合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?
微信网站制作公司有哪些,民生银行办理公司开户怎么在微信网页上查询进度?
制作网站的基本流程,设计网站的软件是什么?
如何在阿里云部署织梦网站?
最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?
音响网站制作视频教程,隆霸音响官方网站?
*请认真填写需求信息,我们会在24小时内与您取得联系。