Select
G1 wants to receive result of computation from G2 and G3

In what order are we going to receive results?
g1<-g2, g1 <-g3org1<-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.
defaultallows 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)
}
}