Go中的Noob

时间:2014-04-06 13:59:49

标签: go

我正试图围绕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次?我尝试了其他代码,我创建了一个频道,然后尝试立即从它接收,我总是得到一个错误,但这似乎工作,我不知道如何。谢谢你的帮助!

2 个答案:

答案 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更简单的版本,所以我不确定它有多大帮助。哎呀。 : - )