我正在tour.golang.org上学习这些示例,我遇到了这段代码,我不太明白:
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x: // case: send x to channel c?
x, y = y, x+y
case <-quit: // case: receive from channel quit?
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() { // when does this get called?
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}我了解通道如何工作的基本知识,但我不了解上面的select语句是如何工作的。本教程的解释是:
select语句允许一个goroutine等待多个通信操作。select阻塞直到它的一个案例能够运行,然后执行该案例。如果多个情况准备就绪,它会随机选择一个。
但是这些案子是如何执行的呢?据我所知,他们是在说:
案例:将x发送到c频道
案例:退出接收
我想我理解第二个只有在退出有一个值的情况下才执行,这个值稍后在go func()中执行。但是,第一次检查是为了什么?而且,在go func()中,我们显然是在打印c的值,但此时c中不应该包含任何内容?我能想到的唯一解释是go func()在调用fibonacci()之后以某种方式执行。我猜这是一条我也不完全理解的大猩猩,它看起来就像魔法。
如果有人能通过这段代码告诉我它在做什么,我将不胜感激。
发布于 2016-01-21 18:12:57
请记住,通道将被阻塞,因此select语句读取:
select {
case c <- x: // if I can send to c
// update my variables
x, y = y, x+y
case <-quit: // If I can receive from quit then I'm supposed to exit
fmt.Println("quit")
return
}default大小写的缺失意味着“如果我不能发送到c,并且我无法从退出中读取,那么在我可以之前阻止它。”
然后,在您的主要过程中,您派生出另一个从c读取以打印结果的函数。
for i:=0; i<10; i++ {
fmt.Println(<-c) // read in from c
}
quit <- 0 // send to quit to kill the main process.这里的关键是记住通道阻塞,您使用的是两个未缓冲的通道。通过使用go派生出第二个函数,您可以从c中消费,这样fibonacci就会继续。
戈鲁丁是所谓的“绿色线”。使用关键字go启动函数调用,将其派生为独立于执行主线的新进程。本质上,main()和go func() ...是同时运行的!这一点很重要,因为我们在这段代码中使用了生产者/消费者模式。
fibonacci生成值并将其发送给c,由main生成的匿名goroutine将使用来自c的值并对其进行处理(在本例中,“处理”只意味着打印到屏幕上)。我们不能简单地生成所有的值然后使用它们,因为c会阻塞它们。此外,fibonacci将永远产生更多的值(或者直到整数溢出为止),因此即使您有一个具有无限长缓冲区的神奇通道,它也永远不会到达使用者。
发布于 2016-01-21 18:12:28
你差不多明白了。
在go func()中,我们显然是在打印c的值,但此时c中不应该包含任何内容?我能想到的唯一解释是go func()在调用fibonacci()之后以某种方式执行。我猜这是个戈鲁蒂
是的,go关键字启动一个goroutine,所以func()将与fibonacci(c,退出)同时运行。来自Println中的通道的接收只会阻塞,直到有什么可接收的东西。
https://stackoverflow.com/questions/34931059
复制相似问题