WaitGroup goroutines with channel

时间:2017-10-12 07:29:23

标签: go

我正在博客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

上草树

3 个答案:

答案 0 :(得分:3)

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

如果您在time.Sleep(time.Second * 1)之后放置wg.Done()之类的内容,则可以看到所有输出行。

答案 1 :(得分:0)

上述博客以以下评论开头:

  编辑:正如this Reddit评论中的effenn指出的那样,本文中的大量信息“危险地不准确”。 OOPS!我已经写了一篇后续/更正文章here供您观看,但我将这篇文章留作“历史目的”。

Reddit commentfollowup article都会描述问题并为您的问题提供解决方案。 (添加time.Sleep(...)以使程序以您期望的方式工作真的很糟糕......)

答案 2 :(得分:0)

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()
}