loong博客

Golang Concurrency - Select

Table of Contents

  • Select Hints

Select Hints

A “select” statement chooses which of a set of possible send or receive operations will proceed.

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.

  • If multiple cases are ready, one is chosen at random.


package main

import (
	"fmt"
	"time"
)

func main() {
	a := make(chan string)
	b := make(chan string)

	go func() {
		time.Sleep(100 * time.Millisecond)
		a <- "你好,世界"
	}()

	go func() {
		time.Sleep(100 * time.Millisecond)
		b <- "Hello World"
	}()

	select {
	case data1 := <-a:
		fmt.Println("got", data1) // may select
	case data2 := <-b:
		fmt.Println("got", data2) // may select
	}
}

  • The default case executes if no other case is ready, avoiding a block.


package main

import (
	"fmt"
)

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

	select {
	case msg1 := <-ch1: // no sender produce data , block
		fmt.Println(msg1)
	case msg2 := <-ch2: // no sender produce data , block
		fmt.Println(msg2)
	default: // select
		fmt.Println("No cases are ready yet")
	}
}

  • Select blocks until at least one channel operation is ready.

The following program will cause a deadlock as no cases are satisfied.


package main

import (
	"fmt"
)

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

	select {
	case msg1 := <-ch1: // no sender produce data , block
		fmt.Println(msg1)
	case msg2 := <-ch2: // no sender produce data , block
		fmt.Println(msg2)
	}
}

  • Select never selects a blocking case.

Sends and receives on nil channels block. Select never selects a blocking case.


package main

import (
	"fmt"
	"math/rand"
)

func main() {
	a, b := make(chan string), make(chan string)
	go func() { a <- "a" }()
	go func() { b <- "b" }()
	if rand.Intn(2) == 0 {
		a = nil
		fmt.Println("nil a")
	} else {
		b = nil
		fmt.Println("nil b")
	}
	select {
	case s := <-a:
		fmt.Println("got", s)
	case s := <-b:
		fmt.Println("got", s)
	}
}

Reference