【问题标题】:WaitGroup goroutines with channel带通道的 WaitGroup goroutines
【发布时间】:2019-06-04 20:20:12
【问题描述】:

我正在从博客https://nathanleclaire.com/blog/2014/02/15/how-to-wait-for-all-goroutines-to-finish-executing-before-continuing/学习WaitGroup

代码:

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    messages := make(chan int)
    var wg sync.WaitGroup

    // you can also add these one at 
    // a time if you need to 

    wg.Add(3)
    go func() {
        defer wg.Done()
        time.Sleep(time.Second * 3)
        messages <- 1
    }()
    go func() {
        defer wg.Done()
        time.Sleep(time.Second * 2)
        messages <- 2
    }() 
    go func() {
        defer wg.Done()
        time.Sleep(time.Second * 1)
        messages <- 3
    }()
    go func() {
        for i := range messages {
            fmt.Println(i)
        }
    }()

    wg.Wait()
}

我认为它应该按顺序打印 3、2 和 1。但是它只打印了 3、2 但缺少 1,这是什么问题?

你可以在https://play.golang.org/p/kZCvDhykYM上树它

【问题讨论】:

    标签: go


    【解决方案1】:

    在最新的messages &lt;- 1 之后,调用延迟的wg.Done(),在程序结束时释放wg.Wait(),程序退出。当一个程序退出时,所有的 goroutine 都会被杀死,所以打印的 goroutine 没有机会打印最新的值。

    如果你在wg.Done() 后面加上time.Sleep(time.Second * 1) 之类的东西,你将能够看到所有的输出行。

    【讨论】:

    • 或者,将其设为wg.Add(4),并将wg.Done() 也放入打印例程中。也就是说,我个人更喜欢将 wg.Wait() 放在 goroutine 中,并使用通道关闭作为“完成”信号:play.golang.org/p/o-EYS_fK2k
    【解决方案2】:

    提到的博客以以下评论开头:

    编辑:正如 effenn 在this Reddit 评论中指出的那样,本文中的很多信息“非常不准确”。哎呀!我写了一篇后续/更正文章here 供您观赏,但我将这篇文章留作“历史目的”。

    Reddit commentfollowup article 都描述了问题并为您的问题提供了解决方案。 (添加time.Sleep(...) 以使程序按您期望的方式运行真的很hacky...)

    【讨论】:

      【解决方案3】:
      package main
      
      import (
          "fmt"
          "sync"
          "time"
      )
      
      func main() {
          messages := make(chan int)
          var wg sync.WaitGroup
      
          // you can also add these one at
          // a time if you need to
      
          wg.Add(3)
          go func() {
              defer wg.Done()
      
              time.Sleep(time.Second * 3)
              messages <- 1
          }()
          go func() {
              defer wg.Done()
      
              time.Sleep(time.Second * 2)
              messages <- 2
          }()
          go func() {
              defer wg.Done()
      
              time.Sleep(time.Second * 1)
              messages <- 3
          }()
      
      exit:
          for {
              select {
              case i, ok := <-messages:
                  if !ok {
                      break exit
                  }
                  fmt.Println(i)
              default:
                  time.Sleep(time.Second)
              }
          }
      
          wg.Wait()
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-18
        • 2019-06-21
        • 1970-01-01
        • 1970-01-01
        • 2017-12-29
        • 1970-01-01
        • 1970-01-01
        • 2020-04-25
        相关资源
        最近更新 更多