Go by Example: Select

select is implemented in src/runtime/select.go 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.”

Details

    1) lock all channel in scase syntax

   2) randomly check if the any channel of the case is ready

       2.1 if case can read, then return (case index, true)

       2.2 if case can write, wrtie data to channelm unlock all channels and return (case index, false)

      2.3 (with default) if all cases are not ready yet, then unlock all channels and return(default index, false)

   3) (without default) if all cases are not ready yet

       3.1 put current goroutine into wait queue

     3.2 block current goroutine until any channel in case is ready.

 4) if ready, go to step 2
package main
import (
    "fmt"
    "time"
)

1) For our example we’ll select across two channels.

func main() {
    c1 := make(chan string)
    c2 := make(chan string)

Each channel will receive a value after some amount of time, to simulate e.g. blocking RPC operations executing in concurrent goroutines.

    go func() {
        time.Sleep(1 * time.Second)
        c1 <- "one"
    }()
    go func() {
        time.Sleep(2 * time.Second)
        c2 <- "two"
    }()

We’ll use select to await both of these values simultaneously, printing each one as it arrives.

    for i := 0; i < 2; i++ {
        select {
        case msg1 := <-c1:
            fmt.Println("received", msg1)
        case msg2 := <-c2:
            fmt.Println("received", msg2)
        }
    }

2) when multiple cases are available, it will select a random one

    ch := make(chan int, 1)
    go func() {
        time.Sleep(1 * time.Second)
        ch <- 1
    }()
    select {
    case <-ch:
        fmt.Println("random 01")
    case <-ch:
        fmt.Println("random 02")
    }

3) use case “default” to prevent deadlock

    ch2 := make(chan int, 1)
    select {
    case <-ch2:
        fmt.Println("got from ch2")
    case <-ch2:
        fmt.Println("got from ch2")
    default:
        fmt.Println("default: not receiving any value")
    }

4) prevent goroutine blocked forever with timeout “time.After”

    ch3 := make(chan int, 1)
    go func() {
        time.Sleep(3 * time.Second)
        ch3 <- 1
    }()
    select {
    case v := <-ch3:
        fmt.Println("receive ch3 value", v)
    case <-time.After(time.Second * 1):
        fmt.Println("timeout!")
    }
}

We receive the values "one" and then "two" as expected.

$ time go run select.go 
received one
received two
random 01
not receiving any value
timeout!

Next example: Inheritence (struct).