Select is a system call in an operating system, and functions such as SELECT, poll, and epoll are often used to build I/O multiplexing models to improve application performance. When it comes to operating on multiple channels in Go, select allows us to operate on multiple channels at the same time. The use of select is similar to that of switch, but remember that each case of select is communication (in this case, communication refers to the receiving or sending of a channel).

First, basic usage

select {
case x := <-c1: // Receive data from channel C1

case y, ok := <-c2: // Receive data from channel C2 and determine if C2 is closed based on ok value

case c3 <- z: // Send z to channel c3:

default: // Execute the default branch if none of the channel communication in the above case can be implemented
}
Copy the code

When the program executes to the top of the SELECT, it evaluates all channels available for communication within the case and blocks until one of them is ready to run. Once one of them is ready to run, the corresponding case is executed. Without default, select blocks forever until channels in one of the cases can communicate. If there is default and channels in all cases cannot communicate, execute the default branch to avoid blocking.

Select (select)

1. Use the default branch to avoid blocking

When there is no executable case branch in the SELECT statement, the select will block. If there is a default branch in the SELECT statement, the default branch statement can be executed to avoid blocking.

2. Implement the timeout mechanism

With timeout events, we can either avoid being stuck waiting for an operation for a long time or do some exception handling. In the following example code, if < -c 5 seconds cannot be executed, the timeout process is directly entered.

func worker(a) {
	select {
	case <-c:
	     // do something
	case <-time.After(5 *time.Second):
    	fmt.Println("timeout")
	    return}}Copy the code

3. Implement the heartbeat mechanism

Using the Ticker with the Time package, we can implement select with a heartbeat mechanism. This allows us to perform periodic tasks while listening to channels:

func worker(a) {
	heartbeat := time.NewTicker(1 * time.Second)
	defer heartbeat.Stop()
	for {
		select {
		case <-c:
			// do something
		case <- heartbeat.C:
			// do something}}}Copy the code

4. Block main

func main(a) {
	bufChan := make(chan int)

	go func(a) {
		for {
			bufChan <- 1
			time.Sleep(time.Second)
		}
	}()

	go func(a) {
		for {
			fmt.Println(<-bufChan)
		}
	}()

	select{}}Copy the code

Using select above, main is blocked forever. Note that there must be a goroutine that is always active, otherwise deadlock will be reported.