简体   繁体   English

Go 缓冲和非缓冲通道故障

[英]Go trouble with buffered and unbuffered channels

I'm a bit confused about the difference between buffered and unbuffered channels in Go.我对 Go 中缓冲通道和非缓冲通道之间的区别有点困惑。 For example, the below code executes fine:例如,下面的代码执行良好:

package main

import "fmt"

func main() {
    messages := make(chan string)
    go func() { messages <- "ping" }()
    msg := <-messages
    fmt.Println(msg)
}

On the other hand, when I pass "ping" to messages in a regular function, there is a deadlock.另一方面,当我将"ping"传递给常规 function 中的消息时,会出现死锁。

package main

import "fmt"

func main() {
    messages := make(chan string)
    func() { messages <- "ping" }()
    msg := <-messages
    fmt.Println(msg)
}

Finally, this is fixed when I use a buffered channel, like so最后,当我使用缓冲通道时,这是固定的,就像这样

package main

import "fmt"

func main() {
    messages := make(chan string, 1)
    func() { messages <- "ping" }()
    msg := <-messages
    fmt.Println(msg)
}

I'm confused why the second case failed.我很困惑为什么第二个案例失败了。 Go By Example says that Go By Example 说

By default channels are unbuffered, meaning that they will only accept sends (chan <-) if there is a corresponding receive (<- chan) ready to receive the sent value.默认情况下,通道是无缓冲的,这意味着如果有相应的接收 (<- chan) 准备好接收发送的值,它们将只接受发送 (chan <-)。 Buffered channels accept a limited number of values without a corresponding receiver for those values.缓冲通道接受有限数量的值,而这些值没有相应的接收器。

In all three cases, isn't msg the sink for messages ?在这三种情况下,不是msg messages器吗?

Unbuffered channels block if they are not read from.如果未读取无缓冲通道,则它们会阻塞。 Buffered channels will not block until they hit capacity.缓冲通道在达到容量之前不会阻塞。

Your first example actually starts a separate go routine which executes the function that tries to write "ping" to the messages channel.您的第一个示例实际上启动了一个单独的 go 例程,该例程执行 function 尝试将“ping”写入消息通道。 It will block until the statement to read from the messages channel executes.它将阻塞,直到从消息通道读取的语句执行。 The statement to read from the messages channel is able to be hit since the function is on a separate goroutine.由于 function 位于单独的 goroutine 上,因此从消息通道读取的语句能够被命中。

Your second example declares and calls a function which attempts to write to the messages channel, but that channel will never be ready to be written to since you are executing on the same main execution thread.您的第二个示例声明并调用 function 尝试写入消息通道,但该通道永远不会准备好写入,因为您正在同一个主执行线程上执行。 The statement to read from the messages channel never hits since you are blocked on writing to the channel.从消息通道读取的语句永远不会命中,因为您在写入通道时被阻止。

The third example, the channel is buffered and can be written to since it can accept 1 value before it blocks.第三个例子,通道被缓冲并且可以被写入,因为它可以在阻塞之前接受 1 个值。

In the first example, the nested function is called from another goroutine.在第一个示例中,嵌套的 function 从另一个 goroutine 调用。 The function starts running and blocks waiting to write the channel. function 开始运行并阻塞等待写入通道。 The main goroutine also runs, and reads from the channel, releasing the block in the second goroutine.主 goroutine 也运行,并从通道读取,释放第二个 goroutine 中的块。

In the second example, the nested function is called by main, and main waits for it to return.在第二个例子中,嵌套的 function 被 main 调用,main 等待它返回。 Since the channel is not buffered, the write operation blocks, which means the main goroutine is blocked and there are no others, so deadlock.由于通道没有缓冲,写操作阻塞,这意味着主协程被阻塞,没有其他协程,所以死锁。

In the third example, the channel is buffered, so the first write does not block.在第三个示例中,通道被缓冲,因此第一次写入不会阻塞。

You may have skimmed over a key word there: "if there is a corresponding receive (<- chan) ready to receive the sent value".您可能已经浏览了那里的一个关键词:“如果有相应的接收 (<-chan)准备好接收发送的值”。

In your first example, the receiver is running concurrently to the sender, so when the sender sends, the receiver is ready to receive at that time.在您的第一个示例中,接收器与发送器同时运行,因此当发送器发送时,接收器此时已准备好接收。 In the second example, they are not running concurrently, so when the sender sends, nothing is ready to receive (because the receive operation won't run until the anonymous function returns), and the send blocks.在第二个示例中,它们没有同时运行,因此当发送方发送时,没有准备好接收(因为接收操作在匿名 function 返回之前不会运行),并且发送阻塞。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM