我只是在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")
}
答案 0 :(得分:3)
您的主线程正在等待done
,然后退出。同时,您的第一个go函数将5个值传递到ch
中,然后发送到done
。
然后从主线程读取done
中的值,并在第二个go函数从ch
读取最后一个值之前发生发生。这样做时,它将退出程序。
请注意,如果您的第二个线程 did 恰好同时从ch
和done
读取,则您的程序将死锁,因为主线程将永远不会在{{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")