Для чего в Go используется тип `*testing.B` и как с ним работать?

Ответ

Да, *testing.B — это ключевой элемент для написания бенчмарков (тестов производительности) в Go. Он передается в качестве аргумента в функции, имя которых начинается с Benchmark.

Основные поля и методы *testing.B:

  • b.N — количество итераций, которое бенчмарк-фреймворк определяет автоматически, чтобы тест выполнялся значимое время (обычно около 1 секунды).
  • b.ResetTimer() — сбрасывает таймер. Используется, чтобы исключить из замеров время на подготовительные операции.
  • b.StopTimer() / b.StartTimer() — позволяют временно останавливать и возобновлять замер времени внутри цикла.

Пример бенчмарка:

package main

import "testing"

// Тестируемая функция
func Sum(a, b int) int {
    return a + b
}

// Глобальная переменная для предотвращения оптимизации компилятора
var result int

func BenchmarkSum(b *testing.B) {
    var r int
    // Цикл выполняется b.N раз
    for i := 0; i < b.N; i++ {
        // Записываем результат, чтобы компилятор не удалил вызов Sum
        r = Sum(1, 2)
    }
    // Присваиваем результат глобальной переменной
    result = r
}

Запуск и анализ:

Бенчмарки запускаются командой go test с флагом -bench.

# Запустить все бенчмарки в пакете и показать выделение памяти
go test -bench=. -benchmem

Вывод будет выглядеть примерно так:

BenchmarkSum-8   1000000000   0.25 ns/op   0 B/op   0 allocs/op

Это означает, что функция Sum выполнялась 1 миллиард раз, и каждая операция в среднем занимала 0.25 наносекунды, не выделяя дополнительной памяти.

Важно присваивать результат вызова тестируемой функции переменной, чтобы компилятор не счел этот вызов "мертвым кодом" (dead code) и не удалил его, что привело бы к некорректным результатам бенчмарка.