今天我们来谈谈Golang的同步等待组

举报
Regan Yue 发表于 2021/08/27 14:11:22 2021/08/27
【摘要】 今天我们来谈谈Golang的同步等待组我们现在开十条子协程,然后当十条子协程全部结束后,主协程立马结束。动动你的小脑袋,想一想应该怎么做?如果是一条子协程的话就很容易实现,当这条子协程结束时让主协程结束就行了。但是我们现在是10条,让任何一条子协程发布让主协程结束的命令都不行,因为你无法确定哪一条子协程是最后结束的。所以我们现在用上了等待组。等待组是什么原理呢?创造一个子协程就登记一下,然后...

今天我们来谈谈Golang的同步等待组

我们现在开十条子协程,然后当十条子协程全部结束后,主协程立马结束。动动你的小脑袋,想一想应该怎么做?如果是一条子协程的话就很容易实现,当这条子协程结束时让主协程结束就行了。但是我们现在是10条,让任何一条子协程发布让主协程结束的命令都不行,因为你无法确定哪一条子协程是最后结束的。所以我们现在用上了等待组。

等待组是什么原理呢?创造一个子协程就登记一下,然后子协程干完活就将其除名,名单除干净了就结束主协程。

我们来看看等待组的有关示例:

func main() {
    fmt.Println(time.Now())
    var wg sync.WaitGroup
    //起一个协程就加一
    wg.Add(1)
    go func() {
        for i:=0;i<5;i++{
            fmt.Println(i)
            //相当于阻塞一秒,读到时间
            <- time.After(time.Second)
        }
        fmt.Println(time.Now())
        //活干完之后减一
        wg.Done()
​
    }()
​
    wg.Add(1)
    go func() {
        var i int
        ticker := time.NewTicker(time.Second)
        for{
            <- ticker.C
            i++
            fmt.Println("秒表",i)
            if i>9 {
                break
            }
        }
        fmt.Println(time.Now())
        wg.Done()
    }()
    //等待组阻塞等待至记录清零为止
    wg.Wait()
    fmt.Println("END")
}

这段代码是建立一条协程就使用wg.Add(1)给等待组加一,然后活干完之后就减一。

WaitGroup 等待一组 goroutine 完成。主 goroutine 调用 Add 来添加要等待的 goroutine 的数量。 然后每个 goroutine 运行并在完成时调用 Done。 同时,Wait 可用于阻塞,直到所有 goroutine 完成。

Add()方法是用来设置等待组中的计数器的值,我们可以理解每个等待组中都有一个计数器,这个计数器可以用来表示这个等待组中要执行的协程数量。如果计数器为零,那么表示被阻塞的协程都被释放了。

Done()方法就是当同步等待组中的某个协程执行完毕后,使同步等待组中的计数器数量减一。

这里一条协程5秒结束,另一条协程10秒结束,那按理来说应该是10秒结束,我们来看看运行结果吧!

2021-08-25 19:10:28.3511953 +0800 CST m=+0.016989401
0
1
秒表 1
2
秒表 2
秒表 3
3
秒表 4
4
秒表 5
2021-08-25 19:10:33.4452142 +0800 CST m=+5.111008301
秒表 6
秒表 7
秒表 8
秒表 9
秒表 10
2021-08-25 19:10:38.4369656 +0800 CST m=+10.102759701
END

下面来谈谈几个需要注意的事项:

  1. 我们使用等待组时不可以在wg.Add()中填入负数,不然会导致报错。报错结果如下:

    panic: sync: negative WaitGroup counter

    这点需要注意。

  2. WaitGroup对象不是一个引用类型

    在通过函数传值时需要使用地址,需要通过指针传值,不然程序会出现死锁!

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。