返回介绍

上卷 程序设计

中卷 标准库

下卷 运行时

源码剖析

附录

12.2.1 并行

发布于 2024-10-12 19:15:50 字数 2326 浏览 0 评论 0 收藏 0

方法 b.RunParallel 创建多个 goroutine 并发测试单个目标。

  • 不能操作计时器。( StartTimerStopTimerResetTimer
  • 不能执行子测试。( Run
func BenchmarkA(b *testing.B) {
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			time.Sleep(time.Microsecond)
		}
	})
 }
$ go test -v -bench . -cpu 1,2,4

=== RUN   TestA
--- PASS: TestA (0.00s)
=== RUN   TestA
--- PASS: TestA (0.00s)
=== RUN   TestA
--- PASS: TestA (0.00s)

BenchmarkA
BenchmarkA         54733             21102 ns/op
BenchmarkA-2      112624             10242 ns/op
BenchmarkA-4      108907             10186 ns/op

PASS
ok      test    3.910s

内部实现

将总次数( b.N , bN )按粒度( grain , ~100µs )分成多个段。
每个 goroutine 每次取一个分段执行。如总任务未完成,则再取一个分段。

使用计数器( cache )记录当前分段任务内部进度。每次调用 PB.Next ,计数器递减。
归零时,将此次分段计入总进度( globalN )。检查总进度,判断是否要再取分段。

|-------------|--------------|-------------|-----//------|
0      g1            g2             g1           g2      bN
type PB struct {
	globalN *uint64 // 总进度(多个 G 进度相加)。
	grain   uint64  // 分段粒度。
	cache   uint64  // 当前分段进度。
	bN      uint64  // 任务总次数(b.N)
}
// benchmark.go

func (b *B) RunParallel(body func(*PB)) {
    
    // 计算分段粒度(~100µs)。
	grain := uint64(0)
	if b.previousN > 0 && b.previousDuration > 0 {
		grain = 1e5 * uint64(b.previousN) / uint64(b.previousDuration)
	}

	n := uint64(0)
	numProcs := b.parallelism * runtime.GOMAXPROCS(0)
    
	var wg sync.WaitGroup
	wg.Add(numProcs)

    // 启动多个 G 并发执行任务。
	for p := 0; p < numProcs; p++ {
		go func() {
			defer wg.Done()
			pb := &PB{
				globalN: &n,
				grain:   grain,
				bN:      uint64(b.N),
			}
			body(pb)
		}()
	}
    
    // 等待。
	wg.Wait()
}
func (pb *PB) Next() bool {
    
    // 刚开始,或当前分段(pb.cache)结束。
	if pb.cache == 0 {
        
        // 累加总进度(pb.globalN)。
		n := atomic.AddUint64(pb.globalN, pb.grain)
        
        // 如果总任务(pb.bN)未结束,则获取下一分段。
		if n <= pb.bN {
			pb.cache = pb.grain
		} else if n < pb.bN+pb.grain {
			pb.cache = pb.bN + pb.grain - n
		} else {
			return false
		}
	}
    
    // 每次执行,递减当前分段计数。
	pb.cache--
    
	return true
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文