likes
comments
collection
share

Go并发系列:3扩展同步原语-3.5 CyclicBarrier

作者站长头像
站长
· 阅读数 45

3.5 CyclicBarrier

在并发编程中,协调多个 Goroutine 的执行顺序是一项常见的任务。在 Go 语言中,虽然没有直接提供类似 Java 中 CyclicBarrier 的原生支持,但我们可以通过 Channel 和 WaitGroup 等原语来实现类似的功能。CyclicBarrier 的作用是使一组 Goroutine 达到某个屏障点后才继续执行。

CyclicBarrier 的基本概念

CyclicBarrier 是一个同步辅助类,允许一组 Goroutine 互相等待,直到所有 Goroutine 都到达一个公共的屏障点(barrier)。这个屏障点可以被反复使用,适合需要重复执行某个步骤的并发任务。

CyclicBarrier 的实现

我们可以使用 Go 的 Channel 和 WaitGroup 来实现一个简单的 CyclicBarrier。以下是一个示例实现:

package main

import (
    "fmt"
    "sync"
)

type CyclicBarrier struct {
    parties   int
    count     int
    mutex     sync.Mutex
    condition *sync.Cond
}

func NewCyclicBarrier(parties int) *CyclicBarrier {
    cb := &CyclicBarrier{
        parties: parties,
        count:   parties,
    }
    cb.condition = sync.NewCond(&cb.mutex)
    return cb
}

func (cb *CyclicBarrier) Await() {
    cb.mutex.Lock()
    defer cb.mutex.Unlock()

    cb.count--
    if cb.count == 0 {
        cb.count = cb.parties
        cb.condition.Broadcast()
    } else {
        cb.condition.Wait()
    }
}

func main() {
    const numGoroutines = 5
    barrier := NewCyclicBarrier(numGoroutines)

    var wg sync.WaitGroup
    wg.Add(numGoroutines)

    for i := 1; i <= numGoroutines; i++ {
        go func(id int) {
            defer wg.Done()
            fmt.Printf("Goroutine %d is waiting at the barrier\n", id)
            barrier.Await()
            fmt.Printf("Goroutine %d has crossed the barrier\n", id)
        }(i)
    }

    wg.Wait()
}

示例分析

在这个示例中,我们实现了一个简单的 CyclicBarrier。CyclicBarrier 的核心是一个计数器(count),以及一个条件变量(condition)。当一个 Goroutine 调用 Await 方法时,计数器会减一。如果计数器减到零,表示所有 Goroutine 都已经到达屏障点,此时重置计数器,并通知所有等待的 Goroutine 继续执行。否则,Goroutine 将等待,直到计数器减到零。

main 函数中,我们创建了一个包含 5 个 Goroutine 的 CyclicBarrier,并启动这 5 个 Goroutine,每个 Goroutine 到达屏障点后等待其他 Goroutine。当所有 Goroutine 都到达屏障点后,它们将继续执行。

CyclicBarrier 的使用场景

CyclicBarrier 适用于需要在多个步骤中重复执行某个任务的并发场景,例如:

  • 并行处理多个任务,每个任务包含多个阶段,各阶段之间需要同步。
  • 多个 Goroutine 需要在某个点上同步,然后再继续执行后续操作。

结论

通过使用 Go 的同步原语,我们可以实现类似 Java 中 CyclicBarrier 的功能。虽然 Go 没有直接提供 CyclicBarrier 类,但灵活运用 Channel 和 WaitGroup 等工具,可以实现各种复杂的并发控制。掌握这些技术,可以帮助我们编写高效、健壮的并发程序,充分发挥多核处理器的性能。

转载自:https://juejin.cn/post/7387934821185880102
评论
请登录