user1928896
user1928896

Reputation: 673

How does channel blocking work in Go?

I'm learning the Go language. Here is an example I've come across. Can someone please explain what is happening here?

package main
import "time"
import "fmt"
func main() {
    c1 := make(chan string)
    c2 := make(chan string)
    go func() {
        time.Sleep(time.Second * 1)
        c1 <- "one"
    }()
    go func() {
        time.Sleep(time.Second * 2)
        c2 <- "two"
    }()
    for i := 0; i < 2; i++ {
      select {
        case msg1 := <-c1:
          fmt.Println("received", msg1)
        case msg2 := <-c2:
          fmt.Println("received", msg2)
        default:
          fmt.Println("Default")
      }
    }
}

Output:

Default
Default
Program Exited

If I comment out the default section

//default:
//    fmt.Println("Default")

the output becomes:

received one
received two
Program exited.

How does the presence of the default case change the way channel blocking works?

Upvotes: 16

Views: 34335

Answers (4)

Anish Mittal
Anish Mittal

Reputation: 1182

Explanation:

c1 := make(chan string) // Creates a channel of type string. [Means only 
strings can be sent/received on this channel]

go func() {
        time.Sleep(time.Second * 1)
        c1 <- "one"
    }()
// func() is a goroutine [As go keyword is placed before, if no go keyword 
here, then it is a simple function].

time.Sleep(time.Second * 1) // here this func() goroutine will sleep for a 
second before passing a value to the channel c1.

c1 <- "one"// value "one" is passed to this channel.

select statement: Here it waits for the goroutines to complete it's task. 
Once a goroutine above finishes, it matches it's case and executes the 
statements. 

Upvotes: -6

Neetish Pathak
Neetish Pathak

Reputation: 9

https://tour.golang.org/concurrency/5

https://tour.golang.org/concurrency/6

See the links given above for example execution. The default case gets executed if no other case is ready. select in golang blocks until one of the cases is ready. Therefore removing default made the execution of other cases possible otherwise it was the one that was ready before others

Upvotes: -4

Filipe Gon&#231;alves
Filipe Gon&#231;alves

Reputation: 21213

This is related to how select statements work in Go.

From the Go documentation on select:

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.

So, without a default case, the code will block until some data is available in either of the channels. It implicitly waits for the other goroutines to wake up and write to their channel.

When you add the default case, it is very likely that the select statement is reached before the other goroutines wake up from sleeping.

So, since there is no data available (yet), and there is a default case, the default case is executed. This is done twice, and it takes less than 1 second. So the program ends up terminating before any of the go routines have a chance to wake up and write to the channel.

Note that this is technically a race condition; there is absolutely no guarantee that the 2 iterations of the loop will run before any of the go routines wake up, so in theory it is possible to have a different output even with a default case, but in practice it is extremely unlikely.

Upvotes: 41

Michael Laszlo
Michael Laszlo

Reputation: 12239

The select statement blocks until at least one case is ready. The Go language specification reads, in part:

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.

In the original code, the default case is ready on both iterations of the loop because there is a delay before anything is sent on c1 or c2.

After you remove the default case, the select statement must wait for data to be available in c1 or c2.

Upvotes: 9

Related Questions