【问题标题】:How to ensure all goroutines terminate without time.Sleep? [duplicate]如何确保所有 goroutines 没有 time.Sleep 终止? [复制]
【发布时间】:2019-09-25 13:20:32
【问题描述】:

我正在尝试使用 go 例程来确定谁首先收到消息。然而,当主 goroutine 终止时,一些 goroutine 仍然挂起。我通过panic 的堆栈跟踪看到了这一点。但是,如果我添加time.Sleep,它们都会终止。我猜这是因为,当主要的 go 例程结束时,Go 运行时找不到时间来终止其他的。

    package main

    import (
        "fmt"
        "time"
    )

    func main() {
        for i := 0; i < 1000000; i++ {
            algo()
        }

        // without this, some goroutines do not terminate
        // time.Sleep(time.Second)

        panic("")
    }

    func algo() {
        c := make(chan int)
        wait := make(chan bool)

        go racer(1, wait, c)
        go racer(2, wait, c)
        go racer(3, wait, c)
        go racer(4, wait, c)
        go racer(5, wait, c)

        // who gets it first
        c <- 5
        close(wait)
    }

    func racer(name int, wait chan bool, c chan int) {
        select {
        case <-wait:
        case v := <-c:
            fmt.Println(name, ":", v)
        }
    }

【问题讨论】:

    标签: go concurrency


    【解决方案1】:

    这正是sync.WaitGroup 的用途。这是一个取自this blog post的玩具示例:

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

    【讨论】:

    • 谢谢 Eli,我知道 WaitGroup。然而,这更像是一个理论问题:“我是对还是错?”。运行时无法真正终止 go 例程,因为主 go 例程在它们之前退出??
    • @JohnFitzgerald:当我降低迭代计数器i 似乎一切都结束了。我认为你的例子过于复杂了。 algo() 一个一个运行(因为 c&lt;-5 块)。尝试简化您的示例以回答您的理论问题
    • 感谢 Eli,这是故意的。我一直试图看到接收消息是随机或按顺序发生的。我想如果我运行它几次,我可以检测到它。 Go Spec 没有说明这一点。
    • @JohnFitzgerald:我建议你综合一个更简单的例子并提出一个新问题。老实说,不清楚你在这里问什么
    猜你喜欢
    • 2013-08-14
    • 2013-03-03
    • 2015-12-10
    • 1970-01-01
    • 2013-04-22
    • 2021-12-19
    • 1970-01-01
    • 2021-10-22
    • 1970-01-01
    相关资源
    最近更新 更多