Go study notes - channel supplement
1. Timeout processing
Timeouts are very important for a program that connects to external resources, or some other operation that takes time to execute.
In the Go language, timeout operations can be handled concisely and elegantly through channel
and .select
c1
Implement an external call through an anonymous function, and return its execution result through the channel after 2 seconds .
func main(){
c1 := make(chan string,1)
go func(){
//设置通道返回结果的时间
time.Sleep(time.Second * 2)
c1 <- "result 1"
}()
}
Through the channel selector select
, handle the timeout operation.
func main(){
select {
case res := <-c1:
//不超时直接返回结果
fmt.Println(res)
case <- time.After(time.Second * 1):
//超时返回下面结果
fmt.Println("timeout 1")
}
}
//timeout 1
Similarly, set the channel to return the result after 2 seconds, but set the timeout period to 3 seconds, and the value in the channel can be returned normally.
func main(){
c2 := make(chan string,1)
go func(){
time.Sleep(time.Second * 2)
c2 <- "result 2"
}()
select {
case res := <-c2:
fmt.Println(res)
case <- time.After(time.Second * 3):
fmt.Println("timeout 2")
}
}
//result 2
2. Non-blocking channel operation
Regular use of channels to send and receive data is blocking.
Using statements with default
clauses select
enables non-blocking send and receive, and even non-blocking multiplex select
.
In the example, if messages
there is a value in , select
put this value into <- messages case
, otherwise default
execute it directly in the clause.
func main(){
messages := make(chan string)
//singals := make(chan bool)
select {
case msg := <-messages:
fmt.Println("received message",msg)
default:
fmt.Println("no message received")
}
}
As you can see by example, default
clauses can provide output to the user when no values are received in the channel.
Ensure that after the channel is defined, the console will not report an error if it is not used to transmit data.
func main(){
messages := make(chan string)
msg := "hi"
//go func() {
// messages <- msg
//}()
select {
case messages <- msg:
fmt.Println("sent message",msg)
//case val := <- messages:
// fmt.Println("received message",val)
default :
fmt.Println("no message sent")
}
}
//no message sent
3. Closing of the channel
After closing a channel, data can no longer be transmitted to this channel.
Closing a channel can be used to transmit information that work has been completed to the receiver of the channel.
func main(){
jobs := make(chan int,5)
done := make(chan bool)
//发送数据
for j:=1;j<=3;j++{
jobs <- j
fmt.Println("sent job",j)
}
close(jobs)
fmt.Println("sent all jobs")
//接收数据
go func(){
time.Sleep(time.Second * 1)
for {
j,more := <-jobs
if more{
fmt.Println("received job",j)
}else{
fmt.Println("received all jobs")
done <- true
return
}
}
}()
//通道同步的方法等待任务结束
<-done
}
We'll use a jobs
channel to communicate main()
the end of task execution in a goroutine to a worker goroutine. close
We channel this when we have no redundant tasks for this worker goroutine jobs
.
Receive data from using j, more := <- jobs
a loop . jobs
Of the values received in this particular binary form, if jobs
has been closed and all values in the channel have been received, then more
the value of will be false
. done
We will use this feature to be notified via the channel when we have completed all tasks .
4. Channel traversal
From the channel closure, it can be seen that after the channel is closed, the values in the channel can still be traversed.
A non-empty channel can be closed, but the remaining values in the channel can still be received.
func main(){
queue := make(chan string,2)
queue <- "on"
queue <- "sky"
close(queue)
for elem := range queue{
fmt.Println(elem)
}
}
To for...range...
traverse the channel usage, you only need to define a variable to store the value.