猿问

Go 通道和延迟

我只是在我的 Ubuntu 64 位环境中试验 Go 通道,并对以下程序产生的输出感到困惑。


我得到输出:0 1 2 3 退出


当我取消注释两个注释行时的输出:0 1 2 3 4 Exit


请解释行为。TIA。


package main


import (

"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")

}


慕的地6264312
浏览 115回答 3
3回答

汪汪一只猫

您的主线程正在等待done,然后退出。同时,您的第一个 go 函数将 5 个值通过管道传输到ch,然后发送到done。then中的值done从主线程中读取,并且恰好发生在第二个 go 函数从中读取最后一个值之前ch。当它这样做时,它退出程序。请注意,如果您的第二个线程确实碰巧同时读取了ch和done,那么您的程序将死锁,因为主线程永远不会接收 ondone并且所有正在运行的 go 线程将被阻塞以等待在通道上接收。

明月笑刀无情

您不是在等待两个 goroutine,而是只将一个值发送done到 2 个接收者,如果第二个接收者恰好是main.使用 aWaitGroup可以简化代码,并允许您轻松等待所需数量的 goroutine。https://play.golang.org/p/MWknv_9AFKpch := make(chan int)var wg sync.WaitGroupwg.Add(1)go func() {&nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; defer close(ch)&nbsp; &nbsp; for i := 0; i < 5; i++ {&nbsp; &nbsp; &nbsp; &nbsp; ch <- i&nbsp; &nbsp; }}()wg.Add(1)go func() {&nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; for message := range ch {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(message)&nbsp; &nbsp; }}()wg.Wait()fmt.Println("Exit")

DIEA

您有两个go并行运行的例程。一个向通道中插入 5 个数字,然后向主线程发出退出信号,另一个从通道中读取数字。请注意,一旦负责将数字排入通道的 go 例程完成,它就会向主线程发出退出信号,而不管读取数字的 go 例程是否完成。因此,您可能会遇到这样一种情况,即入队例程在出队完成之前完成,并且主线程退出。通过添加睡眠,您可以使入队例程的寿命更长一些,并让出队例程有机会在入队例程向主线程发出退出信号之前读取和打印所有数字。要解决这个问题,您可以只在主线程中运行出队代码。在这种情况下,无需在 go 例程中运行它。
随时随地看视频慕课网APP

相关分类

Go
我要回答