Loading

Go语言精进之路读书笔记第46条——为被测对象建立性能基准

46.1 性能基准测试在Go语言中是“一等公民”

性能基准测试在Go语言中和普通的单元测试一样被原生支持的,得到的是“一等公民”的待遇。

我们可以像对普通单元测试那样在*_test.go文件中创建被测对象的性能基准测试,每个以Benchmark前缀开头的函数都会被当作一个独立的性能基准测试。

46.2 顺序执行和并行执行的性能基准测试

#通过-benchtime手动指定b.N的值
go test -v -benchtime 5x -bench . sequential_test.go

#通过-count手动指定执行次数
go test -v -count 2 -bench . sequential_test.go

#通过-cpu手动指定GOMAXPROCS
go test -v -bench . paralell_test.go -cpu 2,4,8
go test -v -bench . paralell_test.go -cpu=2

1.顺序执行

var (
    m     map[int64]struct{} = make(map[int64]struct{}, 10)
    mu    sync.Mutex
    round int64 = 1
)

func BenchmarkSequential(b *testing.B) {
    fmt.Printf("\ngoroutine[%d] enter BenchmarkSequential: round[%d], b.N[%d]\n",
        tls.ID(), atomic.LoadInt64(&round), b.N)
    defer func() {
        atomic.AddInt64(&round, 1)
    }()

    for i := 0; i < b.N; i++ {
        mu.Lock()
        _, ok := m[round]
        if !ok {
            m[round] = struct{}{}
            fmt.Printf("goroutine[%d] enter loop in BenchmarkSequential: round[%d], b.N[%d]\n",
                tls.ID(), atomic.LoadInt64(&round), b.N)
        }
        mu.Unlock()
    }
    fmt.Printf("goroutine[%d] exit BenchmarkSequential: round[%d], b.N[%d]\n",
        tls.ID(), atomic.LoadInt64(&round), b.N)
}

2.并行执行

var (
    m     map[int64]int = make(map[int64]int, 20)
    mu    sync.Mutex
    round int64 = 1
)

func BenchmarkParalell(b *testing.B) {
    fmt.Printf("\ngoroutine[%d] enter BenchmarkParalell: round[%d], b.N[%d]\n",
        tls.ID(), atomic.LoadInt64(&round), b.N)
    defer func() {
        atomic.AddInt64(&round, 1)
    }()

    b.RunParallel(func(pb *testing.PB) {
        id := tls.ID()
        fmt.Printf("goroutine[%d] enter loop func in BenchmarkParalell: round[%d], b.N[%d]\n", tls.ID(), atomic.LoadInt64(&round), b.N)
        for pb.Next() {
            mu.Lock()
            _, ok := m[id]
            if !ok {
                m[id] = 1
            } else {
                m[id] = m[id] + 1
            }
            mu.Unlock()
        }

        mu.Lock()
        count := m[id]
        mu.Unlock()

        fmt.Printf("goroutine[%d] exit loop func in BenchmarkParalell: round[%d], loop[%d]\n", tls.ID(), atomic.LoadInt64(&round), count)
    })

    fmt.Printf("goroutine[%d] exit BenchmarkParalell: round[%d], b.N[%d]\n",
        tls.ID(), atomic.LoadInt64(&round), b.N)
}

46.3 使用性能基准比较工具

benchcmp已废弃,官方推荐用经过统计学方法处理的benchstat。

46.4 排除额外干扰,让基准测试更精确

使用testing.B提供的定时器操作方法排除额外干扰,让基准测试更精确,但不要在RunParallel中使用ResetTimer、StartTimer、StopTimer,因为它们具有全局副作用。

posted @ 2024-03-10 20:15  brynchen  阅读(5)  评论(0编辑  收藏  举报