This article is translated

Original address: golangbot.com/select/

The dead lock and the default

package main

func main(a) {  
    ch := make(chan string)
    select {
    case <-ch:
    }
}
Copy the code

In the above program, we created a CH channel. We try to read ch channel from select statement. The SELECT statement will always block because no other Goroutine is writing to the channel, thus causing a deadlock. The program will panic at run time

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:  
main.main()  
    /tmp/sandbox627739431/prog.go:6 +0x4d
Copy the code

If there is default, this deadlock will not occur because default will be executed when nothing else is ready.

The above program is rewritten with the following default:

package main

import "fmt"

func main(a) {  
    ch := make(chan string)
    select {
    case <-ch:
    default:
        fmt.Println("default case executed")}}Copy the code

Program output:

default case executed
Copy the code

Similarly, default is executed even if a nil only channel is selected.

package main

import "fmt"

func main(a) {  
    var ch chan string
    select {
    case v := <-ch:
        fmt.Println("received value", v)
    default:
        fmt.Println("default case executed")}}Copy the code

In the above program, the value of ch channel is nil, and we try to read the data in ch channel from select. If default does not exist, the select is blocked forever and causes a deadlock. Since we have a default in the selection box, it will be executed and the program will print:

default case executed  
Copy the code

Random selection

When multiple cases in a SELECT statement are ready, one of them is executed randomly.

package main

import (  
    "fmt"
    "time"
)

func server1(ch chan string) {  
    ch <- "from server1"
}
func server2(ch chan string) {  
    ch <- "from server2"

}
func main(a) {  
    output1 := make(chan string)
    output2 := make(chan string)
    go server1(output1)
    go server2(output2)
    time.Sleep(1 * time.Second)
    select {
    case s1 := <-output1:
        fmt.Println(s1)
    case s2 := <-output2:
        fmt.Println(s2)
    }
}
Copy the code

In the above program, server1 and Server Goroutine are called. The main program then sleeps for 1 second. When the SELECT statement is reached. Server1 has written the string from server1 to the output1 channel, and server2 has written the string from server2 to the output2 channel, so it is ready to execute in both cases. If you run this program multiple times, the output will vary between randomly selected cases from Server1 or from Server2 depending on the selection.

Trap – Empty SELECT

package main

func main(a) {  
    select{}}Copy the code

What do you think the output of the above program is?

We know that the SELECT statement blocks until one of these cases is executed. In this case, the SELECT statement has no condition, so it will block forever, resulting in a deadlock. The program will panic:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [select (no cases)]:  
main.main()  
    /tmp/sandbox246983342/prog.go:4 +0x25
Copy the code