我正在浏览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
案例:收到戒烟
我想我知道第二个命令只有在quit有一个值时才执行,稍后在go func()内部完成。但是第一种情况要检查什么?另外,在go func()内部,显然是从c打印值,但是c在那时候不应该包含任何内容?我能想到的唯一解释是go func()在调用fibonacci()之后以某种方式执行。我猜这是一个我也不完全了解的goroutine,就像魔术一样。
如果有人可以通过这段代码告诉我它在做什么,我将不胜感激。
请记住,通道会阻塞,因此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并且我不能从quit中读取,请阻塞直到可以。”
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
fibonacci
Goroutines是所谓的“绿色线程”。使用关键字启动函数调用go会将其分解为一个新进程,该进程独立于执行主线运行。本质上,main()和go func() ...正在同时运行!这很重要,因为我们在此代码中使用了生产者/消费者模式。
main()
go func() ...
fibonacci产生值并将其发送到c,从main派生的匿名goroutine会消耗c并处理它们的值(在这种情况下,“处理它们”仅意味着打印到屏幕上)。我们不能简单地产生所有值然后消费它们,因为c会阻塞。此外,fibonacci它将永远产生更多的值(或无论如何直到整数溢出),因此即使您拥有一个具有无限长缓冲区的魔术通道,也永远不会到达使用者。