2 回答

TA贡献1811条经验 获得超4个赞
为了更好地理解斐波那契的例子,让我们分析不同的部分。
首先是匿名函数
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
“go”关键字将启动一个新的 goroutine,所以现在我们有了 “main” goroutine,而这个,它们将同时运行。
循环告诉我们,我们将执行此命令 10 次:
fmt.Println(<-c)
此调用将阻塞,直到我们从通道接收到整数并打印它。一旦这种情况发生10次,我们将发出信号,表明这个goroutine已经完成了。
quit <- 0
现在让我们回到主 goroutine,当另一个 goroutine 启动时,它调用了函数 “finbonacci”,没有 “go” 关键字,所以这个调用在这里被阻止。
fibonacci(c, quit)
现在让我们分析一下函数
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
我们开始一个无限循环,在每次迭代中,我们将尝试从选择中执行一个案例
第一种情况将尝试将斐波那契的序列值无限期地发送到通道,在某个时候,一旦另一个goroutine到达语句,这种情况将被执行,值将被重新计算,循环的下一次迭代将发生。fmt.Println(<-c)
case c <- x:
x, y = y, x+y
第二种情况还不能运行,因为没有人向“退出”通道发送任何内容。
case <-quit:
fmt.Println("quit")
return
}
经过 10 次迭代后,第一个 goroutine 将停止接收新值,因此第一个选择事例将无法运行
case c <- x: // this will block after 10 times, nobody is reading
x, y = y, x+y
此时,“选择”中没有一个案例可以执行,主goroutine被“阻止”(从逻辑角度来看更像是暂停)。
最后,在某个时候,第一个goroutine将发出信号,表明它已经完成了使用“退出”通道
quit <- 0
这允许执行第二个“选择”情况,这将打破无限循环并允许“斐波那契”函数返回,主函数将能够以干净的方式完成。
希望这有助于您理解斐波那契的例子。
现在,移动到你的代码,你不是在等待匿名的goroutine完成,事实上,它甚至没有完成。您的“b”方法正在发送“1,2,3”并立即返回。
由于它是 main 函数的最后一部分,因此程序将终止。
如果你只看到“1,2”有时是因为“fmt”。Println“语句太慢,程序在可以打印 3 之前终止。

TA贡献1831条经验 获得超9个赞
首先,在 中,语句尝试选择以下两个操作中的第一个完成操作:func fibonacci
select
c <- x
<- quit
它相当容易理解,它试图从一个名为的通道接收值(并忽略接收的值)。<- quit
quit
c <- x
表示发送等于 x 的值(是 x 的副本)。这似乎是解锁,但在Go中,当没有接收器时,通过无缓冲通道发送(在Go tour中进行了解释)阻止。
所以这里的意思是,等待接收器准备好接收值(或缓冲区中的空间,如果它是缓冲通道),这在这个代码中意味着,然后将值发送到接收器。fmt.Println(<-c)
因此,每当评估时,此语句都会取消阻止(完成)。也就是说,循环的每次迭代。<-c
对于您的代码,虽然所有值 , 、 保证通过通道发送(并接收),但返回并因此保留而不保证完成。1
2
3
func b
func main
fmt.Println(3)
在Go中,当返回时,程序终止,未完成的goroutine没有机会完成其工作 - 因此有时它会打印并停止工作。func main
3
- 2 回答
- 0 关注
- 90 浏览
添加回答
举报