当前位置:网站首页>[go] concurrent programming channel
[go] concurrent programming channel
2022-06-24 16:19:00 【Cabbage that wants to become powerful】
List of articles
- One 、channel What is it for ? be used for goroutine Communication between
- Two 、channel It's a data type
- 3、 ... and 、 establish channel
- Four 、channel operation
- 5、 ... and 、 Unbuffered channels
- 6、 ... and 、 There are buffered channels
- 7、 ... and 、close()
- 8、 ... and 、 How to take the value gracefully from the channel loop ( Whether the channel is closed ?)
- Nine 、 One way passage
- Ten 、 Channel summary
- Reference link
One 、channel What is it for ? be used for goroutine Communication between
It doesn't make sense to simply execute functions concurrently . Function and function need to exchange data to reflect the meaning of concurrent function execution .
Although shared memory can be used for data exchange , But shared memory is different goroutine It's easy to have race problems . In order to ensure the correctness of data exchange , Memory must be locked using mutexes , This is bound to cause performance problems .
Go The concurrency model of language is CSP(Communicating Sequential Processes), promote Sharing memory through communication , Instead of communicating through shared memory . This point is in the previous section 【Go】 Concurrent programming It's also mentioned in .
if goroutine yes Go The concurrent executor of a program ,channel It's the connection between them .channel Yes. To make a goroutine Send a specific value to another goroutine Of Communication mechanism .
Go Channels in language (channel) It's a special kind type . A channel is like a conveyor belt or a queue , Always follow First in, first out (First In First Out) The rules of , Ensure the order in which data is sent and received . Every channel is A specific type of conduit , That is to say Statement channel You need to specify the type of element to be transferred .
Two 、channel It's a data type
channel It's a type of , A kind of Reference type . The format for declaring channel types is as follows :( use chan keyword )
var Variable name chan Element type
The variable name is channel Variable name , The element type is this channel The type of data transmitted .
Take a few examples :
var ch1 chan int // Declare a channel that passes integers ch1
var ch2 chan bool // Declare a channel that passes Booleans ch2
var ch3 chan []int // Declare a pass int The passage of the slice ch3
3、 ... and 、 establish channel
1. Statement channel
The channel is a reference type , The null value of the channel type is nil .
package main
import (
"fmt"
)
func main() {
var ch chan int
fmt.Println(ch) // <nil>
}
Output results :
<nil>
If only the channel is declared , The channel cannot be used .
2. In general use make Step by step Statement + establish
The channel needs to use make Function initialization before using .
Use make Function creation channel The format is as follows :
make(chan Element type , [ Buffer size ])
channel The buffer size of is optional .
make Function use example :
ch4 := make(chan int)
ch5 := make(chan bool)
ch6 := make(chan []int)
example :
package main
import (
"fmt"
)
func main() {
ch := make(chan int)
fmt.Println(ch)
}
Output results :
0xc00004a060
Four 、channel operation
Channels have send out (send)、 receive (receive) and close (close) Three operations .
Both sending and receiving use <- Symbol .
Now let's create a channel using the following statement :
ch := make(chan int)
send out
Send a value to the channel .
ch <- 10 // hold 10 Send to ch in
receive
Receive values from a channel .
x := <- ch // from ch Receive values in and assign values to variables x
<-ch // from ch Received value in , Ignore the result
close
We call the built-in close Function to close the channel .
close(ch)
Be careful , The shutdown here is not complete , Only for the sender, the channel is closed . in other words , No more values can be sent to the channel , But you can still receive residual values from it .
The thing to note about closing the tunnel is , Only when the receiver is notified goroutine The channel needs to be closed when all the data is sent .
The channel can be recycled by the garbage collection mechanism , It's not the same as closing a file , It is necessary to close the file after finishing the operation , But close the channel It's not necessary .
The closed channel has the following characteristics :
- Resending a value to a closed channel results in panic.
- Receiving a closed channel will get the value until the channel is empty .
- A receive operation on a closed channel with no value will result in a zero value of the corresponding type .
- Closing a closed channel can result in panic.
5、 ... and 、 Unbuffered channels

Unbuffered channels are also called blocked channels . Let's take a look at the following code :
package main
import (
"fmt"
)
func main() {
ch := make(chan int)
ch <- 10 // Send a value to the channel 10
fmt.Println(" Send successfully ")
}
Output results :
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
D:/liteide/mysource/src/hello/main.go:9 +0x37
It can be seen that although it has passed the compilation , But there was an error . Why does it show up deadlock Wrong ?
Because we use ch := make(chan int) Create unbuffered channels , Unbuffered channels The value can only be sent when someone receives it . It's like the neighborhood you live in has no express cabinet or collection point , The courier has to deliver this item to you when he calls you , Simply put, an unbuffered channel must have a receive to send .
The code above will Blocking stay ch <- 10 This line of code forms a deadlock , How to solve this problem ?
One way is to enable a goroutine To receive value , for example :
package main
import (
"fmt"
)
func recv(c chan int) {
// A function that receives a value from a channel
ret := <-c
fmt.Println(" Successful reception ", ret)
}
func main() {
ch := make(chan int)
go recv(ch) // Enable goroutine Receive value from channel
ch <- 10
fmt.Println(" Send successfully ")
}
Output results :
Successful reception 10
Send successfully
The send operation on the unbuffered channel will block , Until the other goroutine The receiving operation is performed on the channel , Then the value can be sent successfully , Two goroutine Will continue to execute . contrary , If the receive operation is performed first , Receiving party goroutine Will block , Until the other goroutine Send a value... On this channel .
The use of unbuffered channels for communication will result in the transmission and reception of goroutine Synchronization . therefore , Unbuffered channels are also called Synchronous channel .
The unbuffered channel is equivalent to a channel capacity of 0 There are buffer channels for .
6、 ... and 、 There are buffered channels
Another way to solve the above problem is to use channels with buffers .

We can use make Function specifies the capacity of the channel when it initializes the channel , for example :
package main
import (
"fmt"
)
func main() {
ch := make(chan int, 1) // Create a capacity of 1 There are buffer channels for
ch <- 10
fmt.Println(" Send successfully ")
}
Output results :
Send successfully
As long as the capacity of the channel is greater than zero , So this channel is a buffered channel , The capacity of a channel represents the number of elements that can be stored in the channel . Just like the express cabinet in your community has only so many grids , If the grid is full, it won't fit , It's blocking , When someone else takes one, the courier can put one in it .
We can use the built-in len Function to get the number of existing elements in the channel , Use cap Function to get the capacity of a channel , Although we rarely do .
7、 ... and 、close()
You can use the built-in close() Function off channel( If you no longer store values in the channel or take values, remember to close the pipeline )
package main
import "fmt"
func main() {
c := make(chan int)
go func() {
for i := 0; i < 5; i++ {
c <- i
}
close(c) // Close the channel after setting the value
}()
for {
if data, ok := <-c; ok {
fmt.Println(data)
} else {
break
}
}
fmt.Println("main end ")
}
Output results :
0
1
2
3
4
main end
8、 ... and 、 How to take the value gracefully from the channel loop ( Whether the channel is closed ?)
When sending limited data over a channel , We can go through close() Function to close a channel to tell the goroutine Stop waiting . When the channel is closed , Sending a value to this channel raises panic, The value received from this channel is always of type zero . How to judge whether a channel is closed or not ?
Let's look at the following example :
package main
import "fmt"
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
// Turn on goroutine take 0~99 The number of is sent to ch1 in
go func() {
for i := 0; i < 100; i++ {
ch1 <- i
}
close(ch1) // Close after sending ch1
}()
// Turn on goroutine from ch1 Received value in , And send the square of the value to ch2 in
go func() {
for {
i, ok := <-ch1 // After the channel is closed, the value can be taken ok=false
if !ok {
break
}
ch2 <- i * i
}
close(ch2)
}()
// In the main goroutine In the from ch2 Print the received value in
for i := range ch2 {
// ch2 When the channel is closed, it exits for range loop
fmt.Println(i)
}
}
Output results :
0
1
4
9
16
25
36
49
64
81
100
121
...
9409
9604
9801
From the above example, we can see that there are two ways to judge whether the channel is closed when receiving the value :
1. i, ok := <-ch1
2. for i := range ch2
We usually use for range The way .
Nine 、 One way passage
Sometimes we will pass channels as parameters between multiple task functions , Many times we use channels in different task functions to restrict it , For example, the channel can only be sent or received in the function .
Go The language provides a one-way channel to handle this situation . for example , Let's transform the above example as follows :
package main
import "fmt"
func counter(out chan<- int) {
// Send only
for i := 0; i < 100; i++ {
out <- i
}
close(out)
}
func squarer(out chan<- int, in <-chan int) {
// from in Only receive , Square it and send it to out
for i := range in {
out <- i * i
}
close(out)
}
func printer(in <-chan int) {
// Only receive
for i := range in {
fmt.Println(i)
}
}
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go counter(ch1)
go squarer(ch2, ch1)
printer(ch2)
}
Output results :
0
1
4
9
16
25
36
49
...
9409
9604
9801
among ,
1. chan<- int It's a send only channel , Can send but cannot receive ;
2. <-chan int It's a receive only channel , Can receive but cannot send .
It is possible to convert a two-way channel into a one-way channel in function parameter passing and any assignment operation , But vice versa .
Ten 、 Channel summary
channel Common exception summary , Here's the picture :

Be careful :
Close closed channel Will also trigger panic.
Reference link
边栏推荐
- Pageadmin CMS solution for redundant attachments in website construction
- 2021-05-03: given a non negative integer num, how to avoid circular statements,
- 存在安全隐患 路虎召回部分混动揽运
- 2021-04-24: handwriting Code: topology sorting.
- nifi从入门到实战(保姆级教程)——环境篇
- [log service CLS] Tencent cloud log4j/logback log collection best practices
- 一文详解JackSon配置信息
- Learning these 10 kinds of timed tasks, I'm a little floating
- Instruction document for online written examination assistance of smart side school recruitment
- MySQL timestamp format conversion date format string
猜你喜欢

微信公众号调试与Natapp环境搭建

Logging is not as simple as you think

【应用推荐】最近大火的Apifox & Apipost 上手体验与选型建议

Cap: multiple attention mechanism, interesting fine-grained classification scheme | AAAI 2021

【云原生 | Kubernetes篇】Kubernetes基础入门(三)

我与“Apifox”的网络情缘
Advanced programmers must know and master. This article explains in detail the principle of MySQL master-slave synchronization

My network relationship with "apifox"
MySQL進階系列:鎖-InnoDB中鎖的情况

60 divine vs Code plug-ins!!
随机推荐
【prometheus】1. Monitoring overview
The million bonus competition is about to start, and Ti-One will be upgraded to help you win the championship!
CDs view permission check
Goby+awvs realize attack surface detection
Detailed explanation of estab of Stata regression table output
嵌入式开发基础之线程间通信
Script design for automatic login and command return
Siggraph 2022 | truly restore the hand muscles. This time, the digital human hands have bones, muscles and skin
A memory leak caused by timeout scheduling of context and goroutine implementation
Istio FAQ: failed to resolve after enabling smart DNS
A troubleshooting of golang memory leak
ThinkPHP 漏洞利用工具
Greenplum role-based fine-grained permission control
C. Three displays codeforces round 485 (Div. 2)
Implement Domain Driven Design - use ABP framework - domain logic & application logic
Global and Chinese market of inverted syrup 2022-2028: Research Report on technology, participants, trends, market size and share
Using oasis to develop a hop by hop (I) -- Scene Building
April 30, 2021: there are residential areas on a straight line, and the post office can only be built on residential areas. Given an ordered positive array arr
2021-04-24: handwriting Code: topology sorting.
构建Go命令行程序工具链