英文:
Why is go Benchmark function running more than once even though -benchtime=1x?
问题
我写了一个简单的Go基准测试案例,如下所示。它从数据库中获取一个值,检查该值是否为零,然后将其递增并写回数据库。
func BenchmarkMyStuff(b *testing.B) {
require.Equal(b, 1, b.N)
x := GetValueFromDB()
require.Equal(b, 0, x)
x++
WriteValueToDB(x)
}
这个基准测试只有在运行一次时才会通过。这是因为它更新了数据库的值,而x == 0
的检查将失败。为了确保这不会发生,我在该函数的第一行插入了一个require
语句,确保它只运行一次。
这是我运行这个基准测试的方式:
% go test -cpuprofile cpu.prof -memprofile mem.prof -run=XXX -benchtime=1x -bench BenchmarkMyStuff path/to/this/file
请注意,我使用-benchtime=1x
来确保它只运行一次。对吗?这就是手册上所说的。
然而,当我运行这个基准测试时,它运行了两次。为什么呢?第一次通过了BenchmarkMyStuff-6
,然后失败了BenchmarkMyStuff-6
。
英文:
I have written a simply Go Benchmark case like this.
It gets a value from the DB, checks that it is zero, increments it and then writes it back to the DB.
func BenchmarkMyStuff(b *testing.B) {
require.Equal(b, 1, b.N)
x := GetValueFromDB()
require.Equal(b, 0, x)
x++
WriteValueToDB(x)
}
This benchmark will only pass when it is run once. That is because it updates the DB value and the check of x == 0
will fail. To make sure this doesn't happen, I inserted a require
statement at the first line of this function that ensures it will only run once.
And this is how I run this Benchmark:
% go test -cpuprofile cpu.prof -memprofile mem.prof -run=XXX -benchtime=1x -bench BenchmarkMyStuff path/to/this/file
Notice I do -benchtime=1x
to make sure it runs only once. Right? That's what the manual says
Yet when I run this benchmark, it runs twice. Why?
The first time it passes BenchmarkMyStuff-6
and then it fails BenchmarkMyStuff-6
.
答案1
得分: 2
这是一个错误:github.com/golang/go/issues/32051
不幸的是,目前你无法运行一次迭代。但是,即使你只期望一次通过,你仍然应该使用循环。你需要在每次迭代中初始化数据库,但你可以停止计时器以将其排除在基准测试结果之外,这样可以给你一个基准测试结果:
func BenchmarkMyStuff(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
WriteValueToDB(0)
b.StartTimer()
x := GetValueFromDB()
require.Equal(b, 0, x)
x++
WriteValueToDB(x)
}
}
但请注意,这仍然会对require.Equal()
进行基准测试,通常你不会在基准测试中使用断言。
英文:
It's a bug: github.com/golang/go/issues/32051
Unfortunately there isn't much you can do to run one iteration right now. But you should still use a loop, even if you only expect one pass. You will need to initialise the database each iteration but you can stop the timer to exclude this from your benchmark result, this should give you a benchmark result:
func BenchmarkMyStuff(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
WriteValueToDB(0)
b.StartTimer()
x := GetValueFromDB()
require.Equal(b, 0, x)
x++
WriteValueToDB(x)
}
}
But note that this is still also benchmarking require.Equal()
, you would normally not use assertions in your benchmark.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论