• 技术文章 >后端开发 >Golang

    聊聊golang中的Barrier(屏障)

    PHPzhongPHPzhong2023-04-11 09:36:45原创37

    在编写并发代码时,经常需要保证多个goroutine之间的同步和相互之间的令牌或锁,以防止出现数据竞争和竞态条件。Go语言通过chan和sync包提供了一些机制来实现这些同步,但有时候并不够灵活,需要一些更加高级的同步方法,这时候就需要用到屏障。

    屏障是一种同步原语,它用于等待一组goroutine在同一时刻完成某项操作,然后再继续执行下一步操作,这是一种非常常见的同步机制。在Golang中也提供了一种实现屏障的机制,即“Barrier(屏障)”。

    屏障的原理是将一组goroutine分为两个阶段,第一阶段在每个goroutine执行完自己的任务后停止,并等待其他goroutine完成,第二阶段,当所有goroutine都已停止并互相设置信号时,所有goroutine都同时恢复执行。

    Golang在sync包中提供了“WaitGroup”类型,使用Add方法来添加等待的goroutine数量,Done方法用于每个goroutine完成任务后向WaitGroup减少一个计数器,最后,Wait方法阻塞,直到计数器降为零,即所有goroutine都已完成任务,才会继续执行下一步操作。

    但是,WaitGroup有一个缺点,它只能等待一组固定数量的goroutine完成,当有新的goroutine加入时,我们就无法使用它了。这时候,我们可以使用Barrier来解决这个问题。

    Barrier可以用于任意数量的goroutine,并且可以在每个阶段结束时执行任意指定的操作。它包含一个计数器,表示有多少个goroutine正在等待该组操作完成,以及一个函数,用于在每个阶段结束时执行。

    Golang中的“一组等待线程”,可以使用sync包的“WaitGroup(等待组)”来实现:

    var wg sync.WaitGroup
    
    func worker() {
        defer wg.Done()
        // 执行自己的任务
    }
    
    func main() {
        for i := 0; i < n; i++ {
            wg.Add(1)
            go worker()
        }
        // 等待所有线程完成
        wg.Wait()
    }

    现在,我们使用“Barrier”,创建一个可以应用于变化的goroutine的示例:

    package main
    
    import "fmt"
    import "sync"
    
    func main() {
        b := sync.NewCond(&sync.Mutex{})
        done := make(chan bool)
    
        worker := func(id int) {
            defer func() {
                fmt.Printf("Worker %d done\n", id)
                done <- true
            }()
            fmt.Printf("Worker %d processing\n", id)
            b.L.Lock()
            b.Wait() // 等待阻塞直到b.Broadcast()被执行
            b.L.Unlock()
            fmt.Printf("Worker %d resumed\n", id)
        }
    
        go func() {
            for i := 0; i < 10; i++ {
                wg.Add(1)
                go worker(i)
            }
        }()
    
        go func() {
            for i := 0; i < 10; i++ {
                wg.Add(1)
                go worker(i)
            }
        }()
    
        go func() {
            wg.Wait()
            b.Broadcast()
        }()
    
        for i := 0; i < 20; i++ {
            <-done
        }
        fmt.Printf("All workers done\n")
    }

    这个示例创建了20个goroutine,分别分为两个阶段,第一阶段在每个goroutine完成自己的任务后等待,第二阶段等待所有goroutine都完成后再执行操作。

    当两组goroutine被创建后,其中一个goroutine调用了“Wait”并阻塞,直到所有goroutine完成任务。使得其他线程都完成任务时,才释放阻塞,并通过使用“Broadcast”向所有goroutine发送信号,以继续执行下一步操作。

    总之,Golang的Barrier允许您更高级地同步并发操作,并使您的代码更健壮、可靠性更高。

    以上就是聊聊golang中的Barrier(屏障)的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:
    上一篇:一些golang的基础要求和作业要求 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • 详细介绍如何在Golang中捕获错误• docker 怎么安装golang• golang range用法是什么• golang 简单吗• 如何在Golang中设置默认权限掩码
    1/1

    PHP中文网