go的基准测试函数为什么会运行多次,即使设置了-benchtime=1x?

huangapple go评论78阅读模式
英文:

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 &lt; 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.

huangapple
  • 本文由 发表于 2021年9月21日 00:24:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/69257841.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定