Use SELECT to switch coroutines

Fetching values from different concurrent coroutines can be done with the keyword SELECT, which is very similar to the switch control statement and is also known as a communication switch; It behaves like a “are you ready?” polling mechanism; Select listens for data entering a channel, or when a value is sent using a channel.

select {
case u:= <- ch1:
        ...
casev:= <- ch2: ... .default: // no value ready to be received. }Copy the code

The default statement is optional; Fallthrough behavior, similar to normal switches, is not allowed. Execute break or return in either case, and the select ends.

Select does this:

Select to process one of the multiple communication cases listed. If all are blocked, it waits until one of them can be processed. If multiple can be processed, one is selected at random. If no channel operation can be processed and a default statement is written, it executes: Default is always runnable (that is, ready for execution).Copy the code

Using send in SELECT and having default ensures that the send is not blocked! If there is no default, the select will always block.

Select statements implement a listening mode, typically used in (infinite) loops; In some cases, a break statement is used to make the loop exit.

In goroutine_select.go there are two channels ch1 and CH2, and three coroutines PUMp1 (), pump2(), and SUCK (). This is a typical producer-consumer model. In an infinite loop, CH1 and CH2 fill integers with pump1() and pump2(); Suck () also polls for input in an infinite loop, taking integers from CH1 and ch2 and printing them with the SELECT statement. Which case is selected depends on which channel received the message. The program ends 1 second after main.


package main

import (
	"fmt"
	"time"
)

func main(a) {
	ch1 := make(chan int)
	ch2 := make(chan int)

	go pump1(ch1)
	go pump2(ch2)
	go suck(ch1, ch2)

	time.Sleep(1e9)}func pump1(ch chan int) {
	for i := 0; ; i++ {
		ch <- i * 2}}func pump2(ch chan int) {
	for i := 0; ; i++ {
		ch <- i + 5}}func suck(ch1, ch2 chan int) {
	for {
		select {
		case v := <-ch1:
			fmt.Printf("Received on channel 1: %d\n", v)
		case v := <-ch2:
			fmt.Printf("Received on channel 2: %d\n", v)
		}
	}
}
Copy the code
Output: Received on channel 2: 5 Received on channel 2: 6 Received on channel 1: 0 Received on channel 2: 7 Received on channel 2: 8 Received on channel 2: 9 Received on channel 2: 10 Received on channel 1: 2 Received on channel 2: 11 ... Received on channel 2: 47404 Received on channel 1: 94346 Received on channel 1: 94348Copy the code

The output in one second is amazing, and if we count it (goroutine_select2.go), we get around 90,000 numbers.