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)