转到教程 select 语句
go tutorial select statement
我正在研究 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 阻塞直到它的一个 case 可以 运行,然后它执行那个 case。如果多个准备就绪,它会随机选择一个。"
但是这些案件是如何执行的呢?据我所知,他们说:
案例:将x发送到频道c
案例:收到退出
我想我明白第二个只有在 quit 有值时才会执行,这是稍后在 go func() 中完成的。但是第一个案例检查的是什么?此外,在 go func() 内部,我们显然是从 c 中打印值,但此时 c 中不应该有任何内容吗?我能想到的唯一解释是 go func() 以某种方式在调用 fibonacci() 之后执行。我猜这是一个我也不完全理解的 goroutine,它看起来很神奇。
如果有人可以检查这段代码并告诉我它在做什么,我将不胜感激。
你已经差不多明白了。
在 go func() 中,我们显然是从 c 中打印值,但此时 c 中不应该有任何内容吗?我能想到的唯一解释是 go func() 以某种方式在调用 fibonacci() 之后执行。我猜这是一个 goroutine
是的,go 关键字启动一个 goroutine,所以 func() 将 运行 与 fibonacci(c,退出)。从 Println 中的通道接收只是阻塞,直到有东西要接收
记住通道会阻塞,所以 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
个案例意味着 "If I can't send to c and I can't read from quit, block until I can."
然后在你的主进程中你分拆另一个从 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
将继续。
Goroutines 是 so-called "green threads." 使用关键字 go
开始函数调用会将其分离到一个独立于主执行线运行的新进程中。本质上,main()
和go func() ...
同时是运行!这很重要,因为我们在此代码中使用了 producer/consumer 模式。
fibonacci
产生值并将它们发送到 c
,从 main 生成的匿名 goroutine 使用来自 c
的值并处理它们(在本例中,"processing them" 只是意味着打印到屏幕)。我们不能简单地产生所有的值然后消费它们,因为 c
会阻塞。此外,fibonacci
将永远产生更多的值(或者直到整数溢出为止),因此即使您有一个具有无限长缓冲区的魔法通道,它也永远不会到达消费者。
理解此代码示例有两个关键点:
首先,让我们回顾一下无缓冲通道的工作原理。来自 documentation
If the channel is unbuffered, the sender blocks until the receiver has
received the value.
请注意,代码示例中的两个通道 c
和 quit
都是无缓冲的。
其次,当我们使用go
关键字启动一个新的goroutine时,执行将与其他例程并行发生。所以在示例中,我们有两个 go routines 运行:由 func main()
启动的例程,以及 func main()
.
中由 go func()...
启动的例程
我在此处添加了一些内联注释,应该可以使事情更清楚:
包主
导入 "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for { // this is equivalent to a while loop, without a stop condition
select {
case c <- x: // when we can send to channel c, and because c is unbuffered, we can only send to channel c when someone tries to receive from it
x, y = y, x+y
case <-quit: // when we can receive from channel quit, and because quit is unbuffered, we can only receive from channel quit when someone tries to send to it
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() { // this runs in another goroutine, separate from the main goroutine
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit) // this doesn't start with the go keyword, so it will run on the go routine started by func main()
}
我正在研究 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 阻塞直到它的一个 case 可以 运行,然后它执行那个 case。如果多个准备就绪,它会随机选择一个。"
但是这些案件是如何执行的呢?据我所知,他们说:
案例:将x发送到频道c
案例:收到退出
我想我明白第二个只有在 quit 有值时才会执行,这是稍后在 go func() 中完成的。但是第一个案例检查的是什么?此外,在 go func() 内部,我们显然是从 c 中打印值,但此时 c 中不应该有任何内容吗?我能想到的唯一解释是 go func() 以某种方式在调用 fibonacci() 之后执行。我猜这是一个我也不完全理解的 goroutine,它看起来很神奇。
如果有人可以检查这段代码并告诉我它在做什么,我将不胜感激。
你已经差不多明白了。
在 go func() 中,我们显然是从 c 中打印值,但此时 c 中不应该有任何内容吗?我能想到的唯一解释是 go func() 以某种方式在调用 fibonacci() 之后执行。我猜这是一个 goroutine
是的,go 关键字启动一个 goroutine,所以 func() 将 运行 与 fibonacci(c,退出)。从 Println 中的通道接收只是阻塞,直到有东西要接收
记住通道会阻塞,所以 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
个案例意味着 "If I can't send to c and I can't read from quit, block until I can."
然后在你的主进程中你分拆另一个从 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
将继续。
Goroutines 是 so-called "green threads." 使用关键字 go
开始函数调用会将其分离到一个独立于主执行线运行的新进程中。本质上,main()
和go func() ...
同时是运行!这很重要,因为我们在此代码中使用了 producer/consumer 模式。
fibonacci
产生值并将它们发送到 c
,从 main 生成的匿名 goroutine 使用来自 c
的值并处理它们(在本例中,"processing them" 只是意味着打印到屏幕)。我们不能简单地产生所有的值然后消费它们,因为 c
会阻塞。此外,fibonacci
将永远产生更多的值(或者直到整数溢出为止),因此即使您有一个具有无限长缓冲区的魔法通道,它也永远不会到达消费者。
理解此代码示例有两个关键点:
首先,让我们回顾一下无缓冲通道的工作原理。来自 documentation
If the channel is unbuffered, the sender blocks until the receiver has received the value.
请注意,代码示例中的两个通道 c
和 quit
都是无缓冲的。
其次,当我们使用go
关键字启动一个新的goroutine时,执行将与其他例程并行发生。所以在示例中,我们有两个 go routines 运行:由 func main()
启动的例程,以及 func main()
.
go func()...
启动的例程
我在此处添加了一些内联注释,应该可以使事情更清楚: 包主 导入 "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for { // this is equivalent to a while loop, without a stop condition
select {
case c <- x: // when we can send to channel c, and because c is unbuffered, we can only send to channel c when someone tries to receive from it
x, y = y, x+y
case <-quit: // when we can receive from channel quit, and because quit is unbuffered, we can only receive from channel quit when someone tries to send to it
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() { // this runs in another goroutine, separate from the main goroutine
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit) // this doesn't start with the go keyword, so it will run on the go routine started by func main()
}