kevinyan815 / gocookbook

go cook book
MIT License
789 stars 167 forks source link

Go并发编程--循环栅栏CyclicBarrier #32

Open kevinyan815 opened 3 years ago

kevinyan815 commented 3 years ago

这个并发原语是极客时间专栏《Go并发编程实战课》摘录的笔记,补充了点自己的内容

CyclicBarrier也是一种并发同步原语,他允许一组goroutine彼此等待,到达一个共同的执行点(execution point)这个执行点也叫做栅栏(barrier)。同时因为它可以被重复使用,所以叫循环栅栏。具体的机制是,大家都在栅栏前等待,等全部都到齐了,就升起栅栏放行(开始执行)。

CyclicBarrierWaitGroup的功能有点类似。不过,CyclicBarrier更适合用在"固定数量的goroutine等待同一个执行点"的场景中,而且CyclicBarrier也能循环使用。WaitGroup 更适合用在"一个 goroutine 等待一组 goroutine 到达同一个执行点"的场景中,或者是不需要重用的场景中。

循环栅栏CyclicBarrier 是一个开发者借鉴Java CyclicBarrier的功能开发出来的,使用前需要先执行下面的安装命令

go get -u "github.com/marusama/cyclicbarrier"

CyclicBarrier 有两个初始化方法:

func New(parties int) CyclicBarrier
func NewWithAction(parties int, barrierAction func() error) CyclicBarrier

New 方法,它只需要一个参数,来指定循环栅栏参与者的数量;第二个方法是 NewWithAction,额外提供一个函数,可以在每一次到达执行点的时候执行一次。具体的时间点是在最后一个参与者到达之后,但是其它的参与者还未被放行之前。我们可以利用它,做放行之前的一些共享状态的更新等操作。

CyclicBarrier的接口定义如下:


type CyclicBarrier interface {
    // 等待所有的参与者到达,如果被ctx.Done()中断,会返回ErrBrokenBarrier
    Await(ctx context.Context) error

    // 重置循环栅栏到初始化状态。如果当前有等待者,那么它们会返回ErrBrokenBarrier
    Reset()

    // 返回当前等待者的数量
    GetNumberWaiting() int

    // 参与者的数量
    GetParties() int

    // 循环栅栏是否处于中断状态
    IsBroken() bool
}

循环栅栏的使用也很简单。循环栅栏的参与者只需调用 Await 等待,等所有的参与者都到达后,再放行执行下一步。当执行下一步的时候,循环栅栏的状态又恢复到初始的状态了,可以迎接下一轮同样多的参与者。

应用示例

并发趣题--H2O制造工厂