Select

  • G1 wants to receive result of computation from G2 and G3 drawing

  • In what order are we going to receive results? g1<-g2, g1 <-g3 or g1<-g3, g1 <-g2

  • What if G3 was much faster than G2 in one instance, and G2 is faster than G3 in another?

Select

  • select statement is like a switch
  • Each cases specifies communication
  • All chaneel operation are considered simultaneously(同時).
  • select waits until some case is ready to proceed.
  • select will block until any of the case statement is ready.
  • when one the channels is ready, that operation will proceed.
  • very helpful in implementing
    • Timeouts
    • Non-blocking communication

Timeouts

  • select waits until there is event on ch or until timeout is reached.
select {
    case v := <-ch:
        fmt.Println(v)
    case <-time.After( 3 * time.Second):
        fmt.Println("timeout")
}

Non-blocking communication

  • send or receive on a channel, but avoid blocking if the channel is not ready.
  • default allows you to exit a select block without blocking
select {
    case v := <-ch:
        fmt.Println("received message",v)
    cdefault:
        fmt.Println("no message received")
}

Empty Selecat

  • Empty select statement select{} will block forever.
  • Select on nil channel will block forever.
    var ch chan string
    select{
      case v:=<-ch:
      case ch <-v:
    }
    

Exercises

multiplex recv on channel

https://go.dev/play/p/UZb4uRYJ1Cv

package main

import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)

    go func() {
        time.Sleep(1 * time.Second)
        ch1 <- "one"
    }()

    go func() {
        time.Sleep(2 * time.Second)
        ch2 <- "two"
    }()

    // multiplex recv on channel - ch1, ch2
    for {
        select {
        case msg := <-ch1:
            fmt.Println("ch1 :", msg)
        case msg := <-ch2:
            fmt.Println("ch2 :", msg)
        case <-time.After(1 * time.Second):
            fmt.Println("timeout")
            return
        }
    }

    // or
    // for i := 0; i < 2; i++ {
    //     select {
    //     case msg1 := <-ch1:
    //         fmt.Println(msg1)
    //     case msg2 := <-ch2:
    //         fmt.Println(msg2)
    //     }
    // }
}

Timeout

https://go.dev/play/p/VIB1qdIjdkH

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan string, 1)

    go func() {
        time.Sleep(2 * time.Second)
        ch <- "one"
    }()

    // implement timeout for recv on channel ch
    select {
    case msg := <-ch:
        fmt.Print("msg = ", msg)
    case <-time.After(1 * time.Second):
        fmt.Println("timeout")
    }
}

Non-blocking communication

https://go.dev/play/p/3UCb77SW9_s

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan string)

    go func() {
        for i := 0; i < 3; i++ {
            time.Sleep(1 * time.Second)
            ch <- "message"
        }

    }()

    // if there is no value on channel, do not block.
    for i := 0; i < 2; i++ {
        select {
        case m := <-ch:
            fmt.Println(m)
        default:
            fmt.Println("no message received")
        }

        // Do some processing..
        fmt.Println("processing..")
        time.Sleep(1500 * time.Millisecond)
    }
}
© Kimi Tsai all right reserved.            Updated : 2023-07-12 09:04:54

results matching ""

    No results matching ""

    results matching ""

      No results matching ""