【发布时间】:2018-05-29 07:45:05
【问题描述】:
大家好
我一直在学习 Go 的基础知识以及如何使用其基于通道的并发范式。
但是,在使用我编写的一些专注于 select 语句的代码时,我发现了一个奇怪的行为:
func main() {
even := make(chan int)
odd := make(chan int)
quit := make(chan bool)
//send
go send(even, odd, quit)
//receive
receive(even, odd, quit)
fmt.Println("Exiting")
}
func send(e, o chan<- int, q chan<- bool) {
for i := 0; i < 100; i++ {
if i%2 == 0 {
e <- i
} else {
o <- i
}
}
close(e)
close(o)
q <- true
close(q)
}
func receive(e, o <-chan int, q <-chan bool) {
for cont, i := true, 0; cont; i++ {
fmt.Println("value of i", i, cont)
select {
case v := <-e:
fmt.Println("From even channel:", v)
case v := <-o:
fmt.Println("from odd channel:", v)
case v := <-q:
fmt.Println("Got exit message", v)
// return // have also tried this instead
cont = false
}
}
}
当我运行这个简单的程序时,有时 i 累加器最终会在控制台上打印超过 100,而不是以“来自奇数通道:99”结束,for 循环继续输出一个或多个偶数/奇数通道随机归零,好像退出通道的消息在某种程度上被延迟到它的情况下,而是奇数/偶数通道发送更多整数,因此在奇数/偶数通道关闭后不完全退出 for 循环。
value of i 97 true
from odd channel: 97
value of i 98 true
From even channel: 98
value of i 99 true
from odd channel: 99
value of i 100 true
From even channel: 0
value of i 101 true
From even channel: 0
value of i 102 true
from odd channel: 0
value of i 103 true
From even channel: 0
value of i 104 true
Got exit message true
Exiting
我已尝试搜索 case 语句的正确用法,但我无法找到我的代码的问题。
似乎可以在 go playground 上重现相同的行为:my code
感谢您对我的问题的关注。
【问题讨论】:
-
好吧,我发现完全删除 close() 函数会使程序的行为符合我的预期,这种函数仍然是一个非常有趣的行为。
-
我建议你收藏Channel Axioms by Dave Cheney。当我学习这些东西时,它对我帮助很大。
标签: select go concurrency