为了账号安全,请及时绑定邮箱和手机立即绑定

Go 通道和延迟

Go 通道和延迟

Go
慕的地6264312 2023-06-05 18:27:37
我只是在我的 Ubuntu 64 位环境中试验 Go 通道,并对以下程序产生的输出感到困惑。我得到输出:0 1 2 3 退出当我取消注释两个注释行时的输出:0 1 2 3 4 Exit请解释行为。TIA。package mainimport ("fmt"    //"time")func main() {    ch := make(chan int)    done := make(chan bool)    go func() {        for i := 0; i < 5; i++ {            ch <- i        }                //time.Sleep(1 * time.Second)        done <- false    }()    go func() {        for {            select {            case message := <-ch:                fmt.Println(message)            case <-done:                return            }        }    }()    <-done    fmt.Println("Exit")}
查看完整描述

3 回答

?
汪汪一只猫

TA贡献1898条经验 获得超8个赞

您的主线程正在等待done,然后退出。同时,您的第一个 go 函数将 5 个值通过管道传输到ch,然后发送到done

then中的值done从主线程中读取,并且恰好发生在第二个 go 函数从中读取最后一个值之前ch。当它这样做时,它退出程序。

请注意,如果您的第二个线程确实碰巧同时读取了chdone,那么您的程序将死锁,因为主线程永远不会接收 ondone并且所有正在运行的 go 线程将被阻塞以等待在通道上接收。


查看完整回答
反对 回复 2023-06-05
?
明月笑刀无情

TA贡献1828条经验 获得超4个赞

您不是在等待两个 goroutine,而是只将一个值发送done到 2 个接收者,如果第二个接收者恰好是main.

使用 aWaitGroup可以简化代码,并允许您轻松等待所需数量的 goroutine。https://play.golang.org/p/MWknv_9AFKp

ch := make(chan int)

var wg sync.WaitGroup


wg.Add(1)

go func() {

    defer wg.Done()

    defer close(ch)

    for i := 0; i < 5; i++ {

        ch <- i

    }

}()


wg.Add(1)

go func() {

    defer wg.Done()

    for message := range ch {

        fmt.Println(message)

    }


}()


wg.Wait()

fmt.Println("Exit")


查看完整回答
反对 回复 2023-06-05
?
DIEA

TA贡献1820条经验 获得超2个赞

您有两个go并行运行的例程。一个向通道中插入 5 个数字,然后向主线程发出退出信号,另一个从通道中读取数字。

请注意,一旦负责将数字排入通道的 go 例程完成,它就会向主线程发出退出信号,而不管读取数字的 go 例程是否完成。因此,您可能会遇到这样一种情况,即入队例程在出队完成之前完成,并且主线程退出。

通过添加睡眠,您可以使入队例程的寿命更长一些,并让出队例程有机会在入队例程向主线程发出退出信号之前读取和打印所有数字。

要解决这个问题,您可以只在主线程中运行出队代码。在这种情况下,无需在 go 例程中运行它。


查看完整回答
反对 回复 2023-06-05
  • 3 回答
  • 0 关注
  • 114 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信