Brother:

Channel Introduction of Golang

Golang channel concurrent access


Select vs Switch


The one thing they have in common is that they are both handled in case, but otherwise they are almost completely different;

switch.. Interface {} (variable.(type)); The point is that it will be executed in case order.

package main

import "fmt"

func convert(val interface{}) {

	switch t := val.(type) {
	case int:
		fmt.Println("Val is of type int", t)
	case string:
		fmt.Println("Val is a string", t)
	case float64:
		fmt.Println("Val is of type float64", t)
	case float32:
		fmt.Println("Val is of type float32", t)
	case []string:
		fmt.Println("Val is a slice of type string", t)
	default:
		fmt.Println("Val is not one of the above types")}}func main(a) {

	var i interface{}

	i = float32(3.1415926)
	convert(i)

	i = "dashen"
	convert(i)

	i = 100
	convert(i)

	i = []string{"Euler"."Gaussian"}

	convert(i)

}
Copy the code

The output is:

Val forfloat32type3.1415925Val forstringThe type dashen val isinttype100Val is a slice of type string [Eulergauss]Copy the code



And the select.. Case can only handle channel types

That is, each case must be a communication operation, either send or receive


Select will randomly execute a runnable case. If there are no cases to run, it blocks until there are cases to run.

  • Each case must be a communication

  • All channel expressions are evaluated

  • If there are multiple cases that can be executed, Select randomly and fairly selects one to execute. Others will not be executed.

Otherwise: If there is a default clause, execute the statement. If there is no default clause, select blocks until some communication can run; Go does not reevaluate channels or values.



Four basic uses of Select


Random selection


Random Select

package main

import "fmt"

func main(a) {
	var ch1, ch2, ch3 chan int
	var i1, i2 int

	select {
	case i1 = <-ch1:
		fmt.Println("Received a message from pipeline 1 :", i1)
	case ch2 <- i2:
		fmt.Println("Sent a data message to pipeline 2 :", i2)

	case i3, ok := <-ch3:
		if ok {
			fmt.Println("Received data for pipeline 3 :", i3)
		} else {
			fmt.Println("Pipeline 3 has been shut down.")}default:
		fmt.Println("None of the above cases can be run, that is, there is no communication.")}}Copy the code

The output is:

The abovecaseNone is operational, that is, there is no communicationCopy the code

If the default statement block in the above code is removed, the

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [select]:
main.main()
	/Users/shuangcui/go/note/select/2.go:9 +0x108
exit status 2

Copy the code

If the channel in the above code is changed to be cached, for example:

package main

import "fmt"

func main(a) {

	ch1 := make(chan int.1)
	ch2 := make(chan int.1)
	ch3 := make(chan int.1)

	ch6 := make(chan int.1)


	var i1, i2 int

	select {
	case i1 = <-ch1:
		fmt.Println("Received a message from pipeline 1 :", i1)
	case ch2 <- i2:
		fmt.Println("Sent a data message to pipeline 2 :", i2)

	case i3, ok := <-ch3:
		if ok {
			fmt.Println("Received data for pipeline 3 :", i3)
		} else {
			fmt.Println("Pipeline 3 has been shut down.")}case ch6 <- 271828:
		fmt.Println("Sent a data message to pipe 6 :".271828)

	default:
		fmt.Println("None of the above cases can be run, that is, there is no communication.")}}Copy the code

The second case and the fourth case are executable, so the default statement is not used. The output is:

To the pipe2Sends a piece of data:0
Copy the code

or

To the pipe6Sends a piece of data:271828
Copy the code

Both have exactly the same probability of being selected



Timeout control


Suppose that A service needs to invoke interface A and the timeout period is x seconds. How to implement this elegantly and concisely?

Use the select + time. After

reference

package main

import (
	"fmt"
	"time"
)

func main(a) {

	ch := make(chan string)

	go func(a) {
		time.Sleep(time.Second * 2)
		ch <- "Write some value"} ()select {
	case rs := <-ch:
		fmt.Println("The result :", rs)

	case <-time.After(time.Second * 1):
		fmt.Println("Timeout!")}}Copy the code

The output is:

Timeout!Copy the code

Reference:

Go uses time.After to implement timeout control

How to implement timeout control with GO

Go language concurrency model: Use SELECT


About the time. After:

// After waits for the duration to elapse and then sends the current time
// on the returned channel.
// It is equivalent to NewTimer(d).C.
// The underlying Timer is not recovered by the garbage collector
// until the timer fires. If efficiency is a concern, use NewTimer
// instead and call Timer.Stop if the timer is no longer needed.
func After(d Duration) <-chan Time {
	return NewTimer(d).C
}
Copy the code

Receives a value of type INT64 and returns a one-way channel of type Time



Check whether the channel is full


package main

import "fmt"

func main(a) {

	ch := make(chan int.1)

	ch <- 271828

	select {
	case ch <- 31415926:
		fmt.Println("Channel values are :", <-ch)
		fmt.Println("channel vaule is:",<-ch)

	default:
		fmt.Println("The channel is blocked, it's full.")}}Copy the code

The output is:

The channel is blocked, that is, it is fullCopy the code

Change the cache value of the above int channel ch from 1 to 10, then

ch := make(chan int.10)
Copy the code

The execution result is as follows:

The value of the channel is:271828
channel vaule is: 31415926
Copy the code


Use select in the loop


If multiple channels need to be read and the reading is uninterrupted, the for + SELECT mechanism must be used

package main

import (
	"fmt"
	"time"
)

func main(a) {

	i := 0

	ch := make(chan string.0)

	defer func(a) {
		close(ch)
	}()

	go func(a) {
	CuiStartLoop: // CuiStartLoop is a loop body
		for {
			time.Sleep(time.Second * 1)
			fmt.Println(time.Now().Unix())
			fmt.Println("The current value of I is:,i)
			i++

			select {

			case m := <-ch:
				fmt.Println("Output is :",m)
				break CuiStartLoop
			default:
				fmt.Println("Default code block executed")
			}
		}
	}()

	time.Sleep(time.Second * 4)
	ch <- "stop"

}
Copy the code

Output:

1584289065The current value of I is:0To perform thedefaultThe code block1584289066The current value of I is:1To perform thedefaultThe code block1584289067The current value of I is:2To perform thedefaultThe code block1584289068The current value of I is:3The output is stopCopy the code


When no value is passed in, it stays in the Select section, so it works fine without the default code block.

To terminate either for or SELECT, you need a break, but to terminate the for loop directly within the SELECT interval, you can only use a break.


Reference:

In this paper, four usages of Go language Select are mastered


At a lower level (operating system level) :

Select implementation principle

Go Netpoll I/O multiplexing build native network model source in-depth analysis

An EOF – triggered quest 4 (Understanding I/O multiplexing for Golang’s NetFD)