繁体   English   中英

Go 缓冲和非缓冲通道故障

[英]Go trouble with buffered and unbuffered channels

我对 Go 中缓冲通道和非缓冲通道之间的区别有点困惑。 例如,下面的代码执行良好:

package main

import "fmt"

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

另一方面,当我将"ping"传递给常规 function 中的消息时,会出现死锁。

package main

import "fmt"

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

最后,当我使用缓冲通道时,这是固定的,就像这样

package main

import "fmt"

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

我很困惑为什么第二个案例失败了。 Go By Example 说

默认情况下,通道是无缓冲的,这意味着如果有相应的接收 (<- chan) 准备好接收发送的值,它们将只接受发送 (chan <-)。 缓冲通道接受有限数量的值,而这些值没有相应的接收器。

在这三种情况下,不是msg messages器吗?

如果未读取无缓冲通道,则它们会阻塞。 缓冲通道在达到容量之前不会阻塞。

您的第一个示例实际上启动了一个单独的 go 例程,该例程执行 function 尝试将“ping”写入消息通道。 它将阻塞,直到从消息通道读取的语句执行。 由于 function 位于单独的 goroutine 上,因此从消息通道读取的语句能够被命中。

您的第二个示例声明并调用 function 尝试写入消息通道,但该通道永远不会准备好写入,因为您正在同一个主执行线程上执行。 从消息通道读取的语句永远不会命中,因为您在写入通道时被阻止。

第三个例子,通道被缓冲并且可以被写入,因为它可以在阻塞之前接受 1 个值。

在第一个示例中,嵌套的 function 从另一个 goroutine 调用。 function 开始运行并阻塞等待写入通道。 主 goroutine 也运行,并从通道读取,释放第二个 goroutine 中的块。

在第二个例子中,嵌套的 function 被 main 调用,main 等待它返回。 由于通道没有缓冲,写操作阻塞,这意味着主协程被阻塞,没有其他协程,所以死锁。

在第三个示例中,通道被缓冲,因此第一次写入不会阻塞。

您可能已经浏览了那里的一个关键词:“如果有相应的接收 (<-chan)准备好接收发送的值”。

在您的第一个示例中,接收器与发送器同时运行,因此当发送器发送时,接收器此时已准备好接收。 在第二个示例中,它们没有同时运行,因此当发送方发送时,没有准备好接收(因为接收操作在匿名 function 返回之前不会运行),并且发送阻塞。

暂无
暂无

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

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