go tutorial select statement - go

I'm working through the examples at tour.golang.org, and I've encountered this code I don't really understand:
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)
}
I understand the basics of how channels work, but what I don't get is how the above select statement works. The explanation on the tutorial says:
"The select statement lets a goroutine wait on multiple communication operations.
A select blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready."
But how are the cases getting executed? From what I can tell, they're saying:
case: send x to channel c
case: receive from quit
I think I understand that the second one executes only if quit has a value, which is done later inside the go func(). But what is the first case checking for? Also, inside the go func(), we're apparently printing values from c, but c shouldn't have anything in it at that point? The only explanation I can think of is that the go func() somehow executes after the call to fibonacci(). I'm guessing it's a goroutine which I don't fully understand either, it just seems like magic.
I'd appreciate if someone could go through this code and tell me what it's doing.

Remember that channels will block, so the select statement reads:
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
}
The absence of a default case means "If I can't send to c and I can't read from quit, block until I can."
Then in your main process you spin off another function that reads from c to print the results
for i:=0; i<10; i++ {
fmt.Println(<-c) // read in from c
}
quit <- 0 // send to quit to kill the main process.
The key here is to remember that channels block, and you're using two unbuffered channels. Using go to spin off the second function lets you consume from c so fibonacci will continue.
Goroutines are so-called "green threads." Starting a function call with the keyword go spins it off into a new process that runs independent of the main line of execution. In essence, main() and go func() ... are running simultaneously! This is important since we're using a producer/consumer pattern in this code.
fibonacci produces values and sends them to c, and the anonymous goroutine that's spawned from main consumes values from c and processes them (in this case, "processing them" just means printing to the screen). We can't simply produce all the values and then consume them, because c will block. Furthermore fibonacci will produce more values forever (or until integer overflow anyway) so even if you had a magic channel that had an infinitely long buffer, it would never get to the consumer.

There are two key things to understanding this code example:
First, let's review how unbuffered channels work. From the documentation
If the channel is unbuffered, the sender blocks until the receiver has
received the value.
Note that both channels in the code example, c and quit are unbuffered.
Secondly, when we use the go keyword to start a new goroutine, the execution will happen in parallel with other routines. So in the example, we have two go routines running: the routine started by func main(), and the routine started by go func()... inside the func main().
I added some inline comments here which should make things clearer:
package main
import "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()
}

You've pretty much got it.
inside the go func(), we're apparently printing values from c, but c shouldn't have anything in it at that point? The only explanation I can think of is that the go func() somehow executes after the call to fibonacci(). I'm guessing it's a goroutine
Yes, the go keyword starts a goroutine, so the func() will run at the same time as the fibonacci(c, quit). The receive from the channel in the Println simply blocks until there is something to receive

Related

How to reason about Go channel blocking in Go Concurrency Patterns fan-in example?

package main
import (
"fmt"
"math/rand"
"time"
)
func boring(msg string) <-chan string { // Returns receive-only channel of strings.
c := make(chan string)
go func() { // We launch the goroutine from inside the function.
for i := 0; ; i++ {
c <- fmt.Sprintf("%s %d", msg, i)
time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
}
}()
return c // Return the channel to the caller.
}
func fanIn(input1, input2 <-chan string) <-chan string {
c := make(chan string)
go func() {
for {
c <- <-input1
}
}()
go func() {
for {
c <- <-input2
}
}()
return c
}
func main() {
c := fanIn(boring("Joe"), boring("Ann"))
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
fmt.Println("You're both boring; I'm leaving.")
}
This is an example from Rob Pike's talk on Go Concurrency Patterns. I understand the idea behind the fan-in pattern and I understand that the order of messages printed in main is non-deterministic: we just print 10 messages that turn out to be ready.
What I do not completely understand, however, is the order of calls and what blocks what.
Only unbuffered channels are used so, as per the documentation, an unbuffered channel blocks the sender.
The boring function launches a goroutine that sends strings to the unbuffered channel c, which is returned. If I understand correctly, this inner goroutine is launched but doesn't block boring. It can immediately return the channel in main to the fanIn function. But fanIn does almost the same thing: it receives the values from the input channel and sends them to its own channel that is returned.
How does the blocking happen? What blocks what in this case? A schematic explanation would be perfect because, honestly, even though I have an intuitive understanding, I would like to understand the exact logic behind it.
My intuitive understanding is that each send inside boring blocks until the value is received in fanIn, but then the value is immediately sent to another channel so it gets blocked until the value is received in main. Roughly speaking, the three functions are tightly bound to each other due to the use of channels
How does the blocking happen? What blocks what in this case?
Each send on an unbuffered channel blocks if there is no corresponding receive operation on the other side (or if the channel is nil, which becomes a case of having no receiver).
Consider that in main the calls to boring and fanIn happen sequentially. In particular this line:
c := fanIn(boring("Joe"), boring("Ann"))
has order of evaluation:
boring("Joe")
boring("Ann")
fanIn
The send operations in boring("Joe") and boring("Ann") have a corresponding receive operation in fanIn, so they would block until fanIn runs. Hence boring spawns its own goroutine to ensure it returns the channel before fanIn can start receiving on it.
The send operations in fanIn have then a corresponding receive operation in main, so they would block until fmt.Println(<-c) runs. Hence fanIn spawns its own goroutine(s) to ensure it returns the out channel before main can start receiving on it.
Finally main's execution gets to fmt.Println(<-c) and sets everything in motion. Receiving on c unblocks c <- <-input[1|2], and receiving on <-input[1|2] unblocks c <- fmt.Sprintf("%s %d", msg, i).
If you remove the receive operation in main, main can still proceed execution and the program exits right away, so no deadlock occurs.

Go workflow when only sending values to channel

I am learning channels in Go by following this tutorial.
When I only send value to a channel it gives error. Here is the example code.
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1
fmt.Println("Does not work")
}
Here I am just sending value to the channel but not receiving anything. It give an error
fatal error: all goroutines are asleep - deadlock!
But when I run following code it doesn't give any error
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
fmt.Println("did not receive but still works")
}
and prints
did not receive but still works
I couldn't understand why it works in second case while it does not work in first case. Even though I have not received any value for the channel in both cases. Also what is causing the deadlock in first case and how it gets avoided in second case?
Neither example works. In fact, no example that only sends to a channel will ever work, in any traditional sense of "work".
But here's a step through of each, to make it clear:
First example
ch := make(chan int)
This creates an unbuffered channel. Unbuffered channels don't hold any data, they only act as a conduit for communication--all data sent must be received by something else, before the program execution proceeds--on either side of the channel.
ch <- 1
Here you send data on the channel, but nothing is waiting to receive it, so the program waits. In this case, it waits forever, because you never created a receiver for the channel, thus your deadlock.
Second example
c := make(chan int)
Again, create an unbuffered channel.
go sum(s[:len(s)/2], c)
Call the sum function, which, incidentally, will also block forever, for the reasons described above--nothing is receiving on the channel, so it will wait forever. However, in this case, you've called it in a goroutine. The goroutine will run in a separate execution thread, while other bits of the program run. Although, due to never receiving data from the channel, this goroutine will never exit, until the main program exits.
go sum(s[len(s)/2:], c)
Again, you call sum, and again, in a goroutine. So at this point, you have three gorotuines: One running main(), and one each running an invocation of sum(). The latter two will never exit.
Then your program exits. When the program exits, all goroutines (including the two that are stuck forever waiting on your channel) exit.
Since this program exits immediately, the deadlock is never reported, but it does assuredly exist, same as in your first example.

go routine: does select really pick a random case?

Context: https://tour.golang.org/concurrency/5
Hello everyone, I am learning Go following the above link.
The description says "It chooses one at random if multiple are ready."
However, after making the main routine waiting for 2 second, before calling func fibonacci. The channels should be the following after 2 sec:
c: 10 calls to get value from the channel
quit: 0
It looks to me both channels are ready. If "It chooses one at random if multiple are ready" is true, then there is a 50% chance that the first call on the case in fibonacci will get the 0 from the quit channel. However, it is not the case. All 10 numbers will always get printed out before quitting. Hence it does not look like the selection is random. Am I missing something?
package main
import "fmt"
import "time"
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
}()
time.Sleep(2 * time.Second)
fibonacci(c, quit)
}
In addition, the next page:
https://tour.golang.org/concurrency/6
It looks like the default code should print out either tick. or BOOM! at 500 milli second. However, only BOOM! is printed, always. If I changed the time in the default from 50 to 55, then both tick and BOOM get printed. Why is this? Does a After take precedence over a Tick in a select?
package main
import (
"fmt"
"time"
)
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM!")
return
default:
fmt.Println(" .")
time.Sleep(55 * time.Millisecond)
}
}
}
I think you're mistaken about what's happening in your main method... I'm gonna break down what I think is going on for clarity
func main() {
c := make(chan int)
quit := make(chan int) // make a couple channels
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c) // blocked here in goroutine
}
quit <- 0
}() // go func { ... }() - you're both writing this closure and invoking it as a goroutine
time.Sleep(2 * time.Second) // sleep for 2 seconds
fibonacci(c, quit) // call fibonacci passing in the channels
}
so what's actually happened here is you've called this closure as a goroutine then wait 2 seconds during which your goroutine is still sitting in the body of the for loop waiting to receive on c, you call fibonacci which executes as you expect going into the for-select, at which point you keep hitting that code on every iteration of the loop c <- x (it receives, i gets incremented, you receive again, next value until the loop is over due to i == 10). then you proceed to the next line and send on the quit channel, the select executes that condition and your program exits.
As far as what executes first the language spec says;
Execution of a "select" statement proceeds in several steps:
1) For all the cases in the statement, the channel operands of receive
operations and the channel and right-hand-side expressions of send
statements are evaluated exactly once, in source order, upon entering
the "select" statement. The result is a set of channels to receive
from or send to, and the corresponding values to send. Any side
effects in that evaluation will occur irrespective of which (if any)
communication operation is selected to proceed. Expressions on the
left-hand side of a RecvStmt with a short variable declaration or
assignment are not yet evaluated. 2) If one or more of the
communications can proceed, a single one that can proceed is chosen
via a uniform pseudo-random selection. Otherwise, if there is a
default case, that case is chosen. If there is no default case, the
"select" statement blocks until at least one of the communications can
proceed. Unless the selected case is the default case, the respective
communication operation is executed. 3) If the selected case is a
RecvStmt with a short variable declaration or an assignment, the
left-hand side expressions are evaluated and the received value (or
values) are assigned. 4) The statement list of the selected case is
executed.
It's only psuedo random in race conditions, problem is you're not creating a race condition.
In the first snippet of your code, quit is never ready before the for loop. And, in every iteration of the loop, c is ready, and will block until a number is sent through. So there is really nothing select can do but write to c. It does not matter at all if you sleep two seconds.
The second piece of code is not bugged. The select does randomly pick a case indeed. However, Go Playground has a fixed random generator, which means, on Playground, select will always pick one certain case in every run.
You created an unbuffered chan:
c := make(chan int)
This means that anything reading from the chan is going to block until something is written to it. And anything writing to the chan is going to block until something reads from it.
Thus in this code:
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
the <-c blocks until something is put on c. So it sits there waiting until after your time.Sleep() completes, and gets to:
case c <- x:
upon which it alternates blocking back and forth reading one value, writing one value, until it reads 10 values, and then it sends 0 to quit.
To create a buffered chan, you need to specify a size for the buffer.
c := make(chan int, 10)
But note, that even if you do this, it's still not going to behave as you expect, as you're reading all 10 values before you write to quit. You need to put the writers in the same place, and the readers in the same place, not mixing them up.

select in a for loop deadlock's

https://play.golang.org/p/FyIUPkwq0R
Why does the following deadlock?
package main
import (
"fmt"
)
var quit chan bool
var buffer chan string
func main() {
buffer = make(chan string)
quit = make(chan bool)
go func() {
i:=0
for {
select {
case <- quit:
fmt.Println("Bye!")
return
default:
fmt.Println(<-buffer)
}
i++
fmt.Println(i)
}
}()
buffer <- "Go!"
quit <- true // This line dead locks
//buffer <- "Hello" // When I do this instead it works?
//quit <- true // Also when I don't quit it still exit's?
}
This code isn't guaranteed to work properly. You might get lucky, but apparently you've been getting unlucky. You might get lucky and the following might happen:
Let's say we have two goroutines, A and B, where A is the goroutine running main and B is the goroutine running the anonymous function. The following might happen:
B: Execute select; there's nobody writing on the quit channel, so execute the default case
B: Execute <-buffer, so begin blocking, waiting for somebody to write to buffer
A: Write "Go!" to buffer
B: Receive "Go!" and print it. Continue looping.
A: Write true to quit
B: Execute select; A is trying to write to quit, so execute that case. Print "Bye!" and return
A: Since write has finished, continue and return from main
However, this isn't guaranteed to happen. In particular, after reading from buffer, B might keep executing, execute the select, and fall into the default case before A has a chance to write to quit. That's what's probably happening, and would look like this:
B: Execute select; there's nobody writing on the quit channel, so execute the default case
B: Execute <-buffer, so begin blocking, waiting for somebody to write to buffer
A: Write "Go!" to buffer
B: Receive "Go!" and print it. Continue looping
B: Execute select; there's nobody writing on the quit channel, so execute the default case
B: Execute <-buffer, so begin blocking, waiting for somebody to write to buffer
A: Write true to quit, so begin blocking, waiting for somebody to read from quit
Now both A and B are blocked, and since there are no other goroutines in the system, no event can ever unblock either of them, so the system is stuck.
Solution
One way of fixing this would be to make it so that goroutine B reads from the buffer as one of the select cases instead of inside a select case. This way, the select will simply block until either channel becomes available for an action, and your code will behave as you probably wanted it to:
select {
case <-quit:
fmt.Println("Bye!")
return
case str := <-buffer:
fmt.Println(str)
}
See it here on the Go Playground.
Note, however, that since the main goroutine is returning as soon as it writes to the quit channel, and the entire Go program exits as soon as that happens, you may (and probably will) get unlucky and fmt.Println("Bye!") will not execute before the program quits.
Change the select default clause to
default:
fmt.Println("waiting on <-buffer")
fmt.Println(<-buffer)
to see what's going on.
The issue is that the goroutine executes the default branch in the select before main executes quit <- true.
The goroutine blocks at fmt.Println(<-buffer) and the main function blocks at quit <- true.
To prevent the deadlock, receive in the case statement:
select {
case <-quit:
fmt.Println("Bye!")
return
case msg := <-buffer:
fmt.Println(msg)
}
playground example
package main
import (
"fmt"
)
var quit chan bool
var buffer chan string
func main() {
buffer = make(chan string)
quit = make(chan bool)
go func() {
i := 0
for {
select {
case <-quit:
fmt.Println("Bye!")
return
case v := <-buffer:
fmt.Println(v)
default:
// 这里也可能 block
// fmt.Println(<-buffer)
}
i++
fmt.Println(i)
}
}()
buffer <- "Go!"
quit <- true // This line dead locks
//buffer <- "Hello" // When I do this instead it works?
//quit <- true // Also when I don't quit it still exit's?
}

How does make(chan bool) behave differently from make(chan bool, 1)?

My question arises from trying to read a channel, if I can, or write it, if I can, using a select statement.
I know that channels specified like make(chan bool, 1) are buffered, and part of my question is what is the difference between that, and make(chan bool) -- which this page says is the same thing as make(chan bool, 0) --- what is the point of a channel that can fit 0 values in it?
See playground A:
chanFoo := make(chan bool)
for i := 0; i < 5; i++ {
select {
case <-chanFoo:
fmt.Println("Read")
case chanFoo <- true:
fmt.Println("Write")
default:
fmt.Println("Neither")
}
}
A output:
Neither
Neither
Neither
Neither
Neither
(Removing the default case results in a deadlock!!)
Now see playground B:
chanFoo := make(chan bool, 1) // the only difference is the buffer size of 1
for i := 0; i < 5; i++ {
select {
case <-chanFoo:
fmt.Println("Read")
case chanFoo <- true:
fmt.Println("Write")
default:
fmt.Println("Neither")
}
}
B output:
Write
Read
Write
Read
Write
In my case, B output is what I want. What good are unbuffered channels? All the examples I see on golang.org appear to use them to send one signal/value at a time (which is all I need) -- but as in playground A, the channel never gets read or written. What am I missing here in my understanding of channels?
what is the point of a channel that can fit 0 values in it
First I want to point out that the second parameter here means buffer size, so that is simply a channel without buffers (un-buffered channel).
Actually that's the reason why your problem is generated. Un-buffered channels are only writable when there's someone blocking to read from it, which means you shall have some coroutines to work with -- instead of this single one.
Also see The Go Memory Model:
A receive from an unbuffered channel happens before the send on that channel completes.
An unbuffered channel means that read and writes from and to the channel are blocking.
In a select statement:
the read would work if some other goroutine was currently blocked in writing to the channel
the write would work if some other goroutine was currently blocked in reading to the channel
otherwise the default case is executed, which happens in your case A.
Unbuffered channels (created without capacity) will block the sender until somebody can read from them, so to make it work as you expect, you should use two goroutines to avoid the deadlock in the same thread.
For example, with this code: http://play.golang.org/p/KWJ1gbdSqf
It also includes a mechanism for the main func to detect when both goroutines have finished.
package main
import "fmt"
func send(out, finish chan bool) {
for i := 0; i < 5; i++ {
out <- true
fmt.Println("Write")
}
finish <- true
close(out)
}
func recv(in, finish chan bool) {
for _ = range in {
fmt.Println("Read")
}
finish <- true
}
func main() {
chanFoo := make(chan bool)
chanfinish := make(chan bool)
go send(chanFoo, chanfinish)
go recv(chanFoo, chanfinish)
<-chanfinish
<-chanfinish
}
It won't show the alternate Read and Write, because as soon as send writes to the channel, it is blocked, before it can print the "Write", so the execution moves to recv that receives the channel and prints "Read". It will try to read the channel again but it will be blocked and the execution moves to send. Now send can write the first "Write", send to the channel (without blocking because now there is a receiver ready) and write the second "Write". In any case, this is not deterministic and the scheduler may move the execution at any point to any other running goroutine (at least in the latest 1.2 release).

Resources