B.Loop
Вы наверняка знакомы с циклом в бенчмарках (for range b.N):
var sink int
func BenchmarkSlicesMax(b *testing.B) {
// Setup the benchmark.
s := randomSlice(10_000)
b.ResetTimer()
// Run the benchmark.
for range b.N {
sink = slices.Max(s)
}
}
Go сам управляет бенчмарком, определяет разумное значение b.N, и пишет результаты. Это удобно.
Но есть и нюансы:
- Функция бенчмарка выполняется несколько раз, поэтому сетап тоже выполняется несколько раз (и ничего с этим не поделаешь).
- Чтобы сетап не повлиял на результат, приходится вызывать
b.ResetTimer(). - Чтобы компилятор не заоптимизировал тестируемый код, приходится использовать
sink.
Go 1.24 предлагает кое-что получше — testing.B.Loop:
func BenchmarkSlicesMax(b *testing.B) {
// Setup the benchmark.
s := randomSlice(10_000)
// Run the benchmark.
for b.Loop() {
slices.Max(s)
}
}
b.Loop решает все проблемы b.N:
- Функция бенчмарка выполняется один раз, поэтому и сетап тоже выполняется только однажды.
- Все, что находится вне
b.Loop, не влияет на результат, поэтомуb.ResetTimer()не нужен. - Компилятор никогда не оптимизирует вызовы функций внутри
b.Loop.
В общем, с выходом Go 1.24 больше нет причин использовать for range b.N. Переходим на b.Loop!
★ Подписывайтесь на новые заметки.