前往频道和延迟

时间:2019-02-12 18:47:46

标签: go

我只是在Ubuntu 64位环境中尝试Go通道,并与以下程序产生的输出混淆。

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

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

请解释行为。 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")
}

3 个答案:

答案 0 :(得分:3)

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

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

请注意,如果您的第二个线程 did 恰好同时从chdone读取,则您的程序将死锁,因为主线程将永远不会在{{1 }},所有正在运行的go线程都将被阻塞,等待在通道上接收。

答案 1 :(得分:2)

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

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

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

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

答案 2 :(得分:2)

您不必等待两个goroutine,而是仅通过done向2个接收方发送一个值,如果第二个接收方恰好是main,则会死锁。

使用WaitGroup可以简化代码,并使您可以轻松地等待所需的所有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")