Golang development: select multiple options

select is a control structure in Golang, grammatically similar to a switch statement, except that select is used for communication between goroutines. Each case must be a communication operation, either sending or receiving. Select will execute a runnable randomly Case. If there is no case to run, the goroutine will block until there is a case to run.

select multiple selection

The wording of select is basically the same as that of switch case, except that golang's select is a communication control statement. The execution of select must have communication sending or receiving, if not, it will be blocked.

	ch := make(chan bool, 0)
	ch1 := make(chan bool, 0)
	select {
		case ret := <-ch:
			fmt.Println(ret)
		case ret := <-ch1:
			fmt.Println(ret)
	}

If ch and ch1 have no communication data to send, select will block until ch or ch1 has data to send, select will execute the corresponding case to accept the data.

select implements timeout control

We can use the select mechanism to implement a simple timeout control.
First look at the code that the program executes completely

func service(ch chan bool) {
    
    
	time.Sleep(time.Second*3)
	ch<-true
}
func main() {
    
    
	ch := make(chan bool, 0)
	go service(ch)
	select {
    
    
		case ret := <-ch:
			fmt.Println(ret)
		case <-time.After(time.Second*5):
			fmt.Println("timeout")
	}
}

___go_build_main_go #gosetup
true

You can see that 5S is defined using time.After timeout, and the service program executes 3S, so there must be no timeout, which is consistent with expectations.
Let's look at the execution of the timeout again. We will set the execution time of the service program to 6S. The timeout control continues to be 5S, and then look at the execution effect

func service(ch chan bool) {
    
    
	time.Sleep(time.Second*6)
	ch<-true
}
func main() {
    
    
	ch := make(chan bool, 0)
	go service(ch)
	select {
    
    
		case ret := <-ch:
			fmt.Println(ret)
		case <-time.After(time.Second*5):
			fmt.Println("timeout")
	}
}

___go_build_main_go #gosetup
timeout

The execution of the timeout case is actually the same as expected.

select to determine whether the channel is closed

First look at the grammar of receiving data

val,ok <- ch
ok true 正常接收数据
ok false 通道关闭

You can see that there are actually two parameters for receiving data. The second bool value will reflect whether the channel is closed and whether it can accept data normally.

Take a look at the test code.
We wrote a data sender and two data receivers. When the sender closes the channel, the goroutines of the two receivers can judge whether the channel is closed through the above syntax, and decide whether their goroutines are over.

func sender(ch chan int, wg *sync.WaitGroup) {
    
    
	for i:=0;i<10;i++ {
    
    
		ch<-i
	}
	close(ch)
	wg.Done()
}
func receiver(ch chan int, wg *sync.WaitGroup) {
    
    
	for {
    
    
		if val,ok := <-ch;ok {
    
    
			fmt.Println(fmt.Sprintf("%d,%s",val, "revevier"))
		} else {
    
    
			fmt.Println("quit recevier")
			break;
		}
	}
	wg.Done()
}
func receiver2(ch chan int, wg *sync.WaitGroup) {
    
    
	for {
    
    
		if val,ok := <-ch;ok {
    
    
			fmt.Println(fmt.Sprintf("%d,%s",val, "revevier2"))
		} else {
    
    
			fmt.Println("quit recevier2")
			break;
		}
	}
	wg.Done()
}
func main() {
    
    
	ch := make(chan int, 0)
	wg := &sync.WaitGroup{
    
    }
	wg.Add(1)
	go sender(ch, wg)
	wg.Add(1)
	go receiver(ch, wg)
	wg.Add(1)
	go receiver2(ch, wg)
	wg.Wait()
}

Results of the

0,revevier2
2,revevier2
3,revevier2
4,revevier2
5,revevier2
6,revevier2
7,revevier2
1,revevier
9,revevier
quit recevier
8,revevier2
quit recevier2

You can see one data sender and two data receivers. When the channel is closed, both data receivers have received the notification that the channel is closed.
It should be noted that when sending data to a closed channel, the program will panic, and receive data from a closed channel, and will receive zero value data of the channel type that has no reference meaning. Int is 0, string is empty...

select exit timer and other programs

The rotation timer is often used in development, but when the program exits, the rotation timer cannot be closed. In fact, select can solve this problem.
If we have a rotation task, we need a timer, execute logic every 3S, and close this timer after 10S.

Look at the code

func TimeTick(wg *sync.WaitGroup,q chan bool) {
    
    
	defer wg.Done()
	t := time.NewTicker(time.Second*3)
	defer t.Stop()
	for {
    
    
		select {
    
    
		case <-q:
			fmt.Println("quit")
			return
		case <-t.C:
			fmt.Println("seconds timer")
		}
	}
}
func main() {
    
    
	q := make(chan bool)
	wg := new(sync.WaitGroup)
	wg.Add(1)
	go TimeTick(wg,q)
	time.Sleep(time.Second*10)
	close(q)
	wg.Wait()
}

Results of the

seconds timer
seconds timer
seconds timer
quit

Quit the polling timer goroutine gracefully by closing the channel,

Guess you like

Origin blog.csdn.net/feifeixiang2835/article/details/108723186