【问题标题】:proper way of waiting for a go routine to finish等待 goroutine 完成的正确方法
【发布时间】:2014-11-15 06:17:41
【问题描述】:

我想知道在退出程序之前等待 goroutine 完成的正确方法是什么。阅读其他一些答案,bool chan 似乎可以解决问题,如Playground link

func do_stuff(done chan bool) {
    fmt.Println("Doing stuff")
    done <- true
}

func main() {
    fmt.Println("Main")
    done := make(chan bool)
    go do_stuff(done)
    <-done
    //<-done
}

我有两个问题:

  • 为什么

  • 如果我取消最后一行的注释会发生什么?我有一个死锁错误。这是因为通道是空的,没有其他函数向它发送值吗?

【问题讨论】:

  • &lt;- done 有效,因为这正是频道所做的 :)(有关详细信息,请参阅 golang.org/ref/spec#Receive_operatorgolang.org/ref/spec#Send_statements)。关于取消注释第二行如何导致僵局,您是对的。没有任何东西发送到 done 并且 Go 认识到,如果它等待,甚至没有任何东西 可以(例如,没有任何东西在等待网络调用)。

标签: go channel goroutine


【解决方案1】:

为什么&lt;- done 完全有效?

  • 之所以有效,是因为运行时检测到您正在向其他地方的通道写入内容。

如果我取消最后一行的注释会怎样?

  • 运行时足够聪明,可以知道没有任何其他内容正在写入并且它会死锁。

奖励,如果你的内存非常有限,你可以使用done := make(chan struct{})done &lt;- struct{}{}struct{} 保证使用 0 内存。

【讨论】:

  • 你错过了否定吗? “足够聪明”+“死锁”——我认为如果它很聪明,它就不会死锁,而是会给你一个错误,说它会死锁。所以在我看来,要么运行时不够聪明,要么它没有死锁。是哪个?
  • 它足够聪明,因为它会给你一个错误,告诉你它已经死锁了。
【解决方案2】:

收听频道&lt;- done,是一个阻塞操作,所以你的程序将不会继续,直到发送真或假,即done &lt;- true

根据具体情况,您的问题可能会有不同的答案。

例如,假设您想要并行化一系列需要很长时间的函数调用。

我会为此使用 sync

package main

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

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            longOp()
            wg.Done()
        }()
    }
    // will wait until wg.Done is called 10 times
    // since we made wg.Add(1) call 10 times
    wg.Wait()
}

func longOp() {
    time.Sleep(time.Second * 2)
    fmt.Println("long op done")
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-24
    • 2019-02-01
    • 1970-01-01
    • 2012-01-03
    • 1970-01-01
    • 2019-01-30
    • 2019-01-16
    相关资源
    最近更新 更多