Here you are in touch with the most core and important knowledge! Serious study you are great!
This section source location github.com/golang-mini…
What is the channel
Go is a programming language that supports concurrency at the language level, and it has a very specific design philosophy that you don’t communicate through shared memory, you communicate through shared memory, which sounds a little convoluted.
In traditional languages, global variables are used concurrently to share data between different threads by using shared memory to communicate. Go, on the other hand, makes a tunnel between coroutines and transmits data (send and receive) through this tunnel.
For example, we must have had a lot of contact with queues, which are characterized by first-in, first-out, multi-production and multi-consumption. This queue/tunnel is a channel.
A channel is something that communicates between goroutines. Goroutines send and receive messages. Essentially, you’re doing memory sharing between goroutines.
So let’s see what works.
Declaration and initialization
Channels are type dependent, that is, a channel can only pass a value of one type, which needs to be specified when a channel is declared.
The general declaration form of channel:
var chanName chantypeCopy the code
Unlike normal variable declarations, the channel keyword precedes the type, which specifies the type of elements that the channel can pass. Example:
var a chan int // Declare a channel that passes elements of type int
var b chan float64
var c chan string
Copy the code
A channel is a reference type with an initial value of nil. Channels with a value of nil are permanently blocked for receive and send operations, regardless of their type.
So it must be initialized manually by make. Example:
a := make(chan int) // Initialize a channel of type int named a
b := make(chan float64)
c := make(chan string)
Copy the code
Since it’s a queue, it has a size, which it doesn’t specify, and is considered unbuffered (note that size is 0, not 1), which means it has to be received by some other Goroutine, otherwise it will block there. Declare buffered, specify the size can be ok.
a := make(chan int.100)
Copy the code
How to use
Let’s take a closer look at what happens to unbuffered channels and familiarize ourselves with their usage, for example:
func pendingForever(a) {
a := make(chan int)
a <- 1 // Write data to channel
z := <-a // Read data from channel
fmt.Println(z)
}
Copy the code
- Look at the three lines above, line 2
channel
Line 3 writes data fromchannel
Read the data in - But this is in the same method and does not use the Go keyword, which means they are in the same coroutine
We said that a channel is used to communicate with different Goroutines, so it cannot be sent and received in the same coroutine, which cannot achieve the effect of tunnel communication at all. So the above code will deadlock:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chansend]: main.main() ... /4.concurrent/channel.go:7 +0x59
Copy the code
The reason for the deadlock is that there is no other coroutine to receive the data, and the tunnel is unbuffered, so it simply blocks at the sender forever.
It is easy to solve the problem. You can put them in different Goroutines.
func normal(a) {
chanInt := make(chan int)
go func(a) {
chanInt <- 1
}()
res := <-chanInt
fmt.Println(res)
}
Copy the code
Output 1. Buffered channel When no data is sent, the receiver blocks until new data is sent.
In the above code, one sends and one receives, whereas in practice data is often sent continuously. Take a look at this code:
func standard(a) {
chanInt := make(chan int)
go func(a) {
defer close(chanInt)
var produceData = []int{1.2.3}
for _, v := range produceData {
chanInt <- v
}
}()
for v := range chanInt {
fmt.Println(v)
}
}
Copy the code
The output
1
2
3
Copy the code
- The parent coroutine receives the data in a loop.
range chan
Can continuously receive data until the channel is closed. If the channel is closed, it will block forever and cannot be compiled.- The channel must be closed at the sender because the receiver cannot predict whether any data is still unreceived. To the closed
channel
Sending datapanic
. - It is recommended to use
defer
To close the channel, to prevent abnormal procedures not normally closed.
So far we have completed a simple producer-consumer model.
The closing of the channel
Close a channel using the close() function built into the Go language, and again it is recommended to close it using defer, as shown in this example:
defer close(ch)
Copy the code
If a channel is closed, how do I check whether the channel is closed successfully? We can simply read a channel with multiple return values, as in:
x, ok := <-ch
Copy the code
If the value is false, the channel is closed. If the value is false, the channel is closed. If the value is false, the channel is not closed.
func main(a) {
var chanInt chan int = make(chan int.10)
go func(a) {
defer fmt.Println("chanInt is closed")
defer close(chanInt)
chanInt <- 1
}()
res := <-chanInt
fmt.Println(res)
}
Copy the code
The output
chanInt is closed
1
Copy the code
- As stated above, a buffered channel does not need to block waiting for receiving as much as the buffer size allows
- The sender actively closes the channel after sending
- Although the channel has been closed, the receiver can still receive the data.
PS1: A channel can be closed only once. If the channel is closed repeatedly, panic will occur.
PS2: If you pass nil, such as close(nil) panic.
Multisend, multireceive, and unidirectional channels
Let’s combine the previous knowledge to practice!
Function: to achieve a multi – send, multi – receive example.
func send(c chan<- int, wg *sync.WaitGroup) {
c <- rand.Int()
wg.Done()
}
Copy the code
- The sender randomly generates numbers and declares a one-way channel for sending only
- use
sync.WaitGroup
Do wait (forget the previous section ha!)
func received(c <-chan int, wg *sync.WaitGroup) {
for gotData := range c {
fmt.Println(gotData)
}
wg.Done()
}
Copy the code
- Use by receiver
range
To receive the numbers and print them
func main(a) {
chanInt := make(chan int.10)
done := make(chan struct{})
defer close(done)
go func(a) {
defer close(chanInt)
/ / send} ()go func(a){.../ / receive
done <- struct{}{}
}()
<-done
}
Copy the code
- Two channels are used, one channel
chanInt
Data transfer. Anotherdone
End the main coroutine when control is complete - The sending end is responsible for data production and closes the channel after production
- The receiver is responsible for notifying the main coroutine after receiving
The sender
go func(a) {
var wg sync.WaitGroup
defer close(chanInt)
for i := 0; i < 5; i++ {
wg.Add(1)
go send(chanInt, &wg)
}
wg.Wait()
}()
Copy the code
Start 5 coroutines in a row, use WG to do coroutine waiting, send and then finish so that defer can close chanInt
The receiving end
go func(a) {
var wg sync.WaitGroup
for i := 0; i < 8; i++ {
wg.Add(1)
go received(chanInt, &wg)
}
wg.Wait()
done <- struct{} {}} ()Copy the code
Start multiple receivers continuously, exit when the channel is closed, and finally notify Done
Output 5 random numbers, the program normally closed.
5577006791947779410
8674665223082153551
4037200794235010051
6129484611666145821
3916589616287113937
Copy the code
One-way channels limit how functions can be used. They can be used in scenarios where the loop is time-consuming and a data is processed and sent immediately, minimizing memory usage.
summary
This section briefly introduces the Channel in go language. Go language advocates not to communicate through shared memory, but to share memory through communication. Communication between different Goroutines can be completed through channel.
We learned:
channel
Yes Reference type The default value isnil
, need to manuallymake
.- Channels must be in multiple
goroutine
The use of - There are buffered and unbuffered channels and when they block.
- You can use
range
To do the loop reception, channel closing will automatically stop. - Only and must be used on the sending side
defer
Close the channel. - Formal use general multi – send multi – receive, and use
done
Signal notification mode for notification.
At work, the use of channels is more complicated, so stay tuned for select in the next section!