select multiplexing

content

1. The problem of cyclically receiving multiple channels

2. Detailed explanation of select


1. The problem of cyclically receiving multiple channels

When using channels, it is difficult to receive data from multiple channels at the same time. When the channel receives data, it will block if there is no data to receive.

Although it is possible to traverse using the following pattern, the performance will be very poor.

for{
    // 尝试接收ch1通道
    data, ok := <-ch1
    // 尝试接收ch2通道
    data, ok := <-ch2
    // 接收后续通道
    …
}

2. Detailed explanation of select

        The select keyword is provided in the Go language, which can respond to the operations of multiple channels at the same time. Each case of select corresponds to the sending and receiving process of a channel. When the sending and receiving is completed, the response statement in the case will be triggered. Multiple operations pick one in each select to respond.

select{
    case 操作1:
        响应操作1
    
    case 操作2:
        响应操作2
    …
    default: //可选操作,fallthrough 行为,和普通的 switch 相似,是不允许的。
        没有操作情况
}

operate

Statement example

receive arbitrary data

case <- ch:

receive variable

case d :=  <- ch:

send data

case ch <- 100:

What select does is: select to handle one of the listed communication situations, as described below:

  • Execute break or return in any case, and the select ends
  • If both are blocked, it will wait until one of them can handle it
  • If more than one can be handled, choose one at random
  • If there are no channel operations to handle and the default statement is written, it executes: default is always runnable (that's ready, ready to execute). Using the send operation in select and having a default ensures that the send is not blocked! If there is no default, select will always block

The select statement implements a listening mode, usually used in (infinite) loops; in some cases, a break statement is used to cause the loop to exit.

//select  通道的多路复用
package main

import (
   "fmt"
   "time"
)

//往通道中写数据pump1
func pump1(ch chan int){
   for i:=1;; i++{
      ch <- i*2
   }
}

//往通道中写数据pump2
func pump2(ch chan int){
   for i:=1; ; i++{
      ch <- i+2
   }
}

//接收通道中的数据
func suck(ch1, ch2 chan int)  {
   for{
      select{
         case v:= <- ch1:
            fmt.Println("received on channel 1:",v)
         case v2:= <-ch2:
            fmt.Println("received on channel 2:", v2)
      }
   }
}

func main(){
   ch1 := make(chan int)
   ch2 := make(chan int)
   go pump1(ch1)
   go pump2(ch2)
   go suck(ch1, ch2)
    
   time.Sleep(time.Second)
   
}

输出:
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: 94348

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

Guess you like

Origin blog.csdn.net/demored/article/details/124147633