Unidirectional channel
When declaring a channel, we can set send only or receive only. This channel constrained by the operation direction is called unidirectional channel.
- Declare a one-way channel
Send only: Chan < -, receive only: < - Chan
var Channel instance chan<- Element type // Send data only var Channel instance <-chan Element type // Accept data only
Channel instance is channel variable; The element type is the data type transmitted by the channel.
- One way channel usage example
The channel type that can only send data is Chan<-
ch := make(chan int) // Create a channel instance var chSendOnly chan<- int = ch // Send only data and assign ch
The channel type that can only receive data is < - Chan
ch := make(chan int) // Create a channel instance var chRecvOnly <-chan int = ch // Accept only data and assign ch
Use make to create channels that send data only or read-only data
ch := make(<-chan int) var chReadOnly <-chan int = ch <-chReadOnly
A channel that cannot fill data (send data) is meaningless.
Buffered channel
- Create buffered channel
Channel instance := make(chan Channel element type, Buffer size)
Channel element type: Specifies the type of channel transport element
Buffer size: Specifies the maximum number of elements that can be saved by the channel
Channel instance: created channel variable
package main import ( "fmt" ) func main() { ch := make(chan int, 3) // Create a channel with 3 integer element buffer sizes fmt.Println(len(ch)) // View current channel size, 0 ch <- 1 // Send three integer elements to the channel. Because the buffer channel is used, the sender will not block even if no goroutine receives data ch <- 2 ch <- 3 fmt.Println(len(ch)) // View current channel size, 3 }
- Blocking condition
Unbuffered channels can be regarded as buffered channels with a length of always 0. The buffered channel will still be blocked in the following cases: (1) when the buffered channel capacity is full, it will be blocked when trying to send data again; (2) When the buffered channel capacity is empty, it will block when trying to receive data.
- Buffered channel limit buffer size
We know that the channel is a communication bridge between two goroutines. The code using goroutine must have one party's production data and the other party's consumption data. When the producer provides data faster than the consumer consumes data, if the channel does not limit the buffer size, the memory will continue to expand until the application crashes.
Therefore, limiting the buffer size of the channel is conducive to restricting the supply speed of data producers. Data can be processed normally only within the range of data consumer processing capacity + channel size.
Channel multiplexing
Multiplexing usually refers to the process and technology of transmitting multiple signals or data streams on one channel.
The telephone can only receive or send one-way communication at the same time. Telephone and network cable are multiplexed two-way communication modes.
- The general mode receives data from multiple channels at the same time
for { data, ok := <- ch1 // Attempt to receive channel 1 data, ok := <- ch2 // Attempt to receive channel 2 ... // Receive other channels }
- Use the select statement to receive data from multiple channels at the same time
go provides the select keyword and responds to the operations of multiple channels at the same time. Each case corresponds to the sending and receiving process of a channel. When the sending and receiving is completed, the response statement in the case will be triggered. Select a case from a select to respond.
select { case Operation 1: Response action 1 case Operation 2: Response action 2 ... default: When there is no operation }
Operations 1 and 2 are statements related to channel transceiver.
case statement example | significance |
---|---|
case <-ch: | Receive arbitrary data |
case d :=<-ch: | Receive channel variable |
case ch<-100: | send data |
When a related operation occurs, the corresponding case response operation will be executed. When no operation corresponding to case occurs, the statement in default is executed by default.
Continue to use after closing the channel
A channel is a reference object, just like a map. When the reference object does not have any external references, the go runtime will automatically garbage collect (GC) memory. Similarly, the channel can also be actively closed.
- format
Use the close() function to close a channel. Closed channels are still accessible, but there will be some problems.
close(ch)
- Sending data to closed channels will trigger panic
The closed channel will not be set to nil. If data is sent to the closed channel, panic downtime will be triggered.
package main import "fmt" func main() { ch := make(chan int) close(ch) fmt.Printf("ptr:%p cap:%d len:%d\n", ch, cap(ch), len(ch)) ch <- 1 }
- When receiving data from a closed channel, there will be no blocking
package main import ( "fmt" "testing" ) func main() { ch := make(chan int, 2) // Create a channel that can hold two integer elements with a buffer size of 2 // Put two data in the channel, and the channel is full ch <- 0 ch <- 1 // Close the channel. At this time, the data with buffered channel will not be released and the channel does not disappear close(ch) // Traverse all buffered data, and traverse one more for i := 0; i < cap(ch)+1; i++ { // The cap obtains the capacity of the channel; One more element is deliberately taken here, resulting in cross-border access v, ok := <-ch // Fetch data from channel fmt.Println(v, ok) // Print out data status } } /* 0 true 1 true 0 false */
Operation result: the first two lines can normally output the data of the buffered channel, indicating that the data in the channel can still be accessed after the buffered channel is closed.
In the third line, "0 false" indicates the data taken out after the channel is closed. 0 indicates the default zero value of the channel int element, and false indicates that it is not successful because the channel is empty at this time. We can find that after the channel is closed, even if there is no data, the extraction operation will not be blocked, but the extracted data is not normally transmitted.