• Go并发可视化解释 - sync.WaitGroup


    场景

    Avito是一名校车司机,他帮助4个Gopher孩子上学。每天,Avito在他们的社区等待孩子们。他不知道孩子们需要多长时间,但他确切地知道有4个孩子他需要等待。

    1f83d3a42168b86cb20f4a40bb2c46dd.png
    1*aZnEggopv4Tsbyyj3e5JFg.png

    当一个孩子准备好时,他/她会说:Done(),将计数器减1。Avito仍然被阻塞,因为计数器仍然大于0。他必须等到所有其他孩子准备好。

    58d79d0dae2e0697c1b55c127815dce0.png
    1*qouGWmMAqY2CDrzz5widhQ.png

    如果有两个孩子同时准备好,它们的同时准备会导致WaitGroup出现不一致吗?绝对不会。与sync包中的大多数其他组件一样,WaitGroup具有内置的同步机制,以处理并发。因此,计数器减少了准备好的孩子数量。

    165e096cd0a5945983a8bdc41594df20.png
    1*057bX4zo_LCzEkdzGyDYpA.png

    在最后一个孩子准备好后,Avito启动引擎,将他们送到学校。

    af2c92caf10e838b7f80e03b3812c797.png
    1*rjH8OR3t7QgUx-dO-Iszeg.png

    就是这样!正如我所说,sync.WaitGroup很简单。

    超时

    如果一个孩子花费太多时间准备,他们会不会因此迟到?如果Avito在时间到达时不管怎样都开始行驶会更好吗?嗯,Golang倾向于保持一切尽可能简洁,因此与其他编程语言中的CountDownLatch(例如Java中的)不同,sync.WaitGroup默认情况下不支持超时。在这种情况下,选择语句可能会有所帮助。

    1. func main() {
    2. wg := sync.WaitGroup{}
    3. wg.Add(1)
    4. go func() {
    5. defer wg.Done()
    6. time.Sleep(5 * time.Second)
    7. }()
    8. done := make(chan bool)
    9. go func() {
    10. wg.Wait()
    11. close(done)
    12. }()
    13. select {
    14. case <-done:
    15. log.Println("All done")
    16. case <-time.After(1 * time.Second):
    17. log.Println("Hit timeout")
    18. }
    19. }

    孩子等待

    在上面的示例中,Avito(主Goroutine)等待孩子(子Goroutines)。当我们希望子Goroutines等待主Goroutine时,WaitGroup也可以使用。想象一下孩子们正在进行体育课。Torcher - 体育老师,在学生中主持比赛。他向WaitGroupAdd(1),并要求所有孩子在相同的WaitGroupWait()

    7211eba3e3606da7ce01f8f0efcfd83d.png
    1*btDQK4QKsu1HkEpfJDa2EA.png

    当Torcher调用wg.Done()时,计数器变为0,允许所有孩子同时开始奔跑。

    759f0b500c2eba454a2a7eaf39a77aaa.png
    1*VkV3VlRTx5jxXhauBH0_Dg.png

    展示你的代码!

    1. package main
    2. import (
    3. "log"
    4. "sync"
    5. "time"
    6. )
    7. func main() {
    8. kids := []string{"Partier", "Stringer", "Candier", "Swimmer"}
    9. wg := sync.WaitGroup{}
    10. wg.Add(len(kids))
    11. for _, kid := range kids {
    12. go func(name string) {
    13. defer wg.Done()
    14. prepare(name)
    15. }(kid)
    16. }
    17. log.Printf("Avito: I'm waiting for %d kids\n", len(kids))
    18. wg.Wait()
    19. log.Println("Avito: The kids are all ready, go!")
    20. }
    21. func prepare(name string) {
    22. log.Printf("%v: I'm preparing for school\n", name)
    23. time.Sleep(2 * time.Second)
    24. log.Printf("%v: I'm ready\n", name)
    25. }
  • 相关阅读:
    左值和右值
    Request和Response
    Flink源码阅读笔记——StreamGraph、JobGraph、ExecutionGraph
    Unity DOTS技术(五)Archetype,Chunk,NativeArray
    P4491 [HAOI2018] 染色
    geecg-uniapp 同源策略 数据请求 获取后台数据 进行页面渲染 ui库安装 冲突解决(3)
    05_Docker-Compose
    C# 设计模式 观察者模式示例
    Linux读写文件
    超声波清洗机怎么挑选好坏?四大热度火爆的清洗机速速入手
  • 原文地址:https://blog.csdn.net/weixin_37604985/article/details/133956552