我正试图围绕Go中的并发模式,并且被#69
中的这个例子搞糊涂了package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
特别是,我不知道如何
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
应该可行,因为我们所做的只是制作频道,现在我们“接收”了10次?我尝试了其他代码,我创建了一个频道,然后尝试立即从它接收,我总是得到一个错误,但这似乎工作,我不知道如何。谢谢你的帮助!
答案 0 :(得分:4)
fmt.Println(<-c)
将阻止,直到从频道中读取内容。由于我们在一个单独的goroutine中启动for
循环,这意味着循环的第一次迭代将只是闲置并等到有东西要读。
然后fibonacci
函数启动,并将数据推送到通道。这将使循环唤醒并开始打印。
我希望现在更有意义。
答案 1 :(得分:2)
我正在给你一个上面代码的简短版本,我觉得应该更容易理解。 (我解释下面的差异。)考虑一下:
// http://play.golang.org/p/5CrBSu4wxd
package main
import "fmt"
func fibonacci(c chan int) {
x, y := 0, 1
for {
c <- x
x, y = y, x+y
}
}
func main() {
c := make(chan int)
go fibonacci(c)
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
}
这是一个更直接的版本,因为您的main
功能显然只是从频道打印10个值,然后退出;只要需要新的值,就会有一个填充通道的背景goroutine。
这个备用版本会删除 quit 频道,因为背景goroutine在main()
完成时就会死掉(在这么简单的例子中不需要明确地删除它)。
当然,这个版本也会使用select{}
,这是#69的主题。但是看看两个版本如何完成同样的事情,除了杀死背景goroutine,也许可以帮助理解select
正在做什么。
特别注意,如果fibonacci()
的第一个语句有time.Sleep()
,那么for循环会挂起很长时间,但最终会有效。
希望这有帮助!
P.S。:刚刚意识到这个版本只是一个比#68更简单的版本,所以我不确定它有多大帮助。哎呀。 : - )