background
I believe everyone is familiar with the built-in data structure channel of Go. Channel plays a very important role in the Go language.
- Channels can help achieve communication and synchronization between goroutines.
- The Go language implements the CSP (Communicating Sequencial Process) model through goroutines and channels.
Robe Pike, one of the inventors of the Go language, said the following:
Don't communicate by sharing memory, share memory by communicating.
The hidden meaning in this sentence is actually to hope that Go developers use channels to communicate between goroutines.
There are 2 types of channels:
- bi-directional channel: you can send data to the channel and receive data from the channel
uni-directional channel
- send-only channel: You can only send data to the channel and cannot receive data from the channel, otherwise it will compile an error
- receive-only channel: can only receive data from the channel, not send data to the channel, otherwise it will compile an error
A typical usage scenario of a one-way channel is as a function or method parameter to control that data can only be sent to or received from the channel to avoid misoperation.
package main
import (
"fmt"
)
// send-only channel
func testSendChan(c chan<- int) {
c <- 20
}
// receive-only channel
func testRecvChan(c <-chan int) {
result := <-c
fmt.Println("result:", result)
}
func main() {
ch := make(chan int, 3)
testSendChan(ch)
testRecvChan(ch)
}
For example, in the above program, the parameter of testSendChan
is a send-only channel, and the parameter of testRecvChan
is a receive-only channel.
The actual parameter ch
is a two-way channel, and the Go runtime will convert the two-way channel into a one-way channel and pass it to the corresponding function.
question
The above example uses a one-way channel as a function parameter, a two-way channel as a function parameter, and the make function creates a two-way channel.
So can we use make to create a one-way channel? Is there any actual usage scenario for the one-way channel created by make? Are there potential pits?
Let's take a look at the following two questions:
Topic 1
ch := make(<-chan int)
close(ch)
fmt.Println("ok")
- A: print ok
- B: Error at runtime: fatal error - deadlock
- C: runtime error: painic
- D: Compilation failed
Topic 2
c := make(chan<- int)
close(c)
fmt.Println("ok")
- A: print ok
- B: Error at runtime: fatal error - deadlock
- C: runtime error: painic
- D: Compilation failed
You can pause for a while and think about what the answers to these two questions will be.
Parse
Answer
The answer to question 1 is D. Question 1 creates a receive-only channel, which can only receive values from the channel and cannot send values to the channel.
The receive-only channel cannot be closed. If the close operation is performed, the following error will be reported:
./main.go:9:7: invalid operation: close(ch) (cannot close receive-only channel)
The answer to question 2 is A. Question 2 creates a send-only channel, which can only send values to the channel, but cannot receive values from the channel.
For send-only channels, it can be closed normally.
Why can't receive-only channel be closed, but send-only channel can be closed?
This is because a receive-only channel means that it can only receive data from this channel. The user has only read permission to this channel, but no write permission to the channel, that is, it cannot send data to the channel or perform close operations on the channel.
So the answer to question 1 is D and the answer to question 2 is A.
Derived problem
// send-only channel
func testSendChan(c chan<- int) {
c <- 20
}
// receive-only channel
func testRecvChan(c <-chan int) {
result := <-c
fmt.Println("result:", result)
}
func main() {
ch := make(chan int, 3)
testSendChan(ch)
testRecvChan(ch)
}
The above code is a typical usage scenario of a one-way channel. The function parameter is a two-way channel, and the function parameter is a one-way channel. We can send data to the channel through the send-only channel, and receive data from the channel through the receive-only channel. This is easy to understand. But it should be noted that the function argument here is a bidirectional channel .
Careful developers may have a question. For the above two questions, make creates a one-way channel, and either can only send data to this channel, or can only receive data from this channel, unlike make in the above code. The created channel is a bidirectional channel.
The question is, is there any practical use for the one-way channel created by make ?
For example, the send-only channel created by make(chan<- int)
can only send data to this channel, but cannot read data from this channel, what's the use?
For example, the receive-only channel created by make(<-chan int)
can only receive data from this channel, but cannot send data to this channel, what's the use?
Regarding this issue, in fact, there have been relatively big disputes among the big brothers of the Go language.
Brad Fitzpatrick of the Golang team complained that the compiler should report an error directly to make to create a one-way channel, because the one-way channel created by make is useless.
I'm surprised the compiler permits create send- or receive-only channels: ------ package main import "fmt" func main() { c := make(<-chan int) fmt.Printf("%T\n", c) } ------ Is that an accident? I can't see what utility they'd have.
The feedback given by Russ Cox , the head of the Go language, is: I think there is no clear reason for the compiler to prohibit make from creating a one-way channel, because if there is an illegal operation on a one-way channel, the compiler will still report an error, and let the compiler directly prohibit make from creating it. One-way channels will increase the complexity of Go design, and it is unnecessary and worth the loss.
I can't see a reason to disallow it either though. All I am saying is that explicitly disallowing it adds complexity to the spec that seems unnecessary. What bugs or problems does it avoid to make this special exclusion in the rules for make? Russ
Recommended reading
- Go Quiz: Considerations for Channels from Go Interview Questions
- Go Quiz: From the Go interview questions, look at the precautions of channel in select scenarios
Summarize
- For
channel
, sending data tochannel
and receiving data fromchannel
will block. For
nil channel
and bufferedchannel
, the mechanism of sending and receiving data is shown in the following table:channel nil empty Not empty not full full send data to channel block Sent successfully Sent successfully block Receive data from channel block block Received successfully Received successfully close channel panic Closed successfully Closed successfully Closed successfully channel
After being closed:- Sending data to the closed
channel
will trigger a panic. To receive data from the closed
channel
, it will read the data inchannel
first. If the data is read, continue to read data fromchannel
to get the zero value of the element type stored inchannel
.data, ok := <- c
对于上面的代码,如果channel
c
关闭了,c
里读数据,当c
里还有数据时,data
is the corresponding read value, the value of ---5b9166b37368899c464e67166163e5ddok
istrue
.c
读完了,那data
就是零值,ok
的值是false
。-
channel
After being closed, if it is closed again, it will cause panic.
- Sending data to the closed
The operating mechanism of
select
is as follows:- Select an executable non-blocking
case
branch, if multiplecase
branches are not blocked, one will be randomly selectedcase
branch execution, andcase
The order in which branches are written in the code does not matter. - If all
case
branches are blocked, thedefault
branch will be executed. - If there is no
default
branch, thenselect
will block until there is acase
branch that does not block.
- Select an executable non-blocking
open source address
Articles and sample code are open sourced on GitHub: Beginner, Intermediate, and Advanced Tutorials in Go .
Official account: coding advanced. Follow the official account to get the latest Go interview questions and technology stacks.
Personal website: Jincheng's Blog .
Zhihu: Wuji .
Welfare
I have compiled a back-end development learning material package for you, including programming language entry to advanced knowledge (Go, C++, Python), back-end development technology stack, interview questions, etc.
Follow the official account "coding advanced", send a message backend to receive a gift package, this information will be updated from time to time, and add information that I think is valuable. You can also send a message "join the group " to communicate and learn with your peers and answer questions.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。