Reputation: 1268
I'm trying to wrap my head around concurrency patterns in Go and was confused by this example from #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)
}
In particular, I don't see how
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
is supposed to work, since all we did was make the channel, and now we "receive" from it 10 times? I tried out other code where I create a channel and then try to receive from it right away and I always get an error, but this seems to work and I can't quite see how. Thanks for any help!
Upvotes: 2
Views: 106
Reputation: 49265
fmt.Println(<-c)
will block until there's something to read from the channel. Since we start the for
loop in a separate goroutine, it means the first iteration of the loop will simply sit idly and wait until there's something to read.
Then the fibonacci
function starts, and pushes data down the channel. This will make the loop wake up and start printing.
I hope it makes better sense now.
Upvotes: 4
Reputation: 454
I’m giving you a shorter version of the code above, which I think should be easier to understand. (I explain the differences below.) Consider this:
// 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)
}
}
This is a more straightforward version because your main
function is clearly just printing 10 values from the channel, and then exiting; and there is a background goroutine that is filling the channel as long as a new value is needed.
This alternate version drops the quit channel, because the background goroutine simply dies when main()
finishes (no need to kill it explicitly in such a simple example).
Of course this version also kills the use of select{}
, which is the topic of #69. But seeing how both versions accomplish the same thing, except killing of the background goroutine, can perhaps be a good aid in understanding what select
is doing.
Note, in particular, that if fibonacci()
had a time.Sleep()
as its first statement, the for loop would hang for that much time, but would eventually work.
Hope this helps!
P.S.: Just realized this version is just a simpler version than #68, so I’m not sure how much it’ll help. Oops. :-)
Upvotes: 2