未初始化的通道如何表现?

Posted

技术标签:

【中文标题】未初始化的通道如何表现?【英文标题】:How does a non initialized channel behave? 【发布时间】:2016-12-25 05:32:58 【问题描述】:

我有一个结构,其中包含一个未初始化的通道。

当我写入它时,例程按预期阻塞,但从未通知读者管道中有东西。

我很惊讶没有错误,我想知道 Go 正在做什么。

在下面的示例中,既不打印消息 pushed 也不打印 got it。 (取消注释初始化,它会像魅力一样工作)

type MyStruct struct 
    over chan bool


func main() 
    nonInitialized := &MyStruct
    // nonInitialized.over = make(chan bool)
    go func() 
        for i := 0; i < 10; i++ 
            select 
            case <-nonInitialized.over:
                fmt.Println("got it")
            default:
                // proceed
            
            fmt.Println("do some stuff")
            time.Sleep(10 * time.Millisecond)
        
        panic("took too long")
    ()
    // push on the non initialized channel
    fmt.Println("pushing")
    nonInitialized.over <- true
    fmt.Println("pushed")

这里是游乐场https://play.golang.org/p/76zrCuoeoh

(我知道我应该初始化通道,这不是问题的目的,我想知道在未初始化通道的 Go 中发生了什么。)

【问题讨论】:

【参考方案1】:

channel type 的“未初始化”字段或变量将具有所有通道类型的 zero value,即 nil。那么让我们来看看nil 通道或对它的操作的行为。

值得在一篇文章中收集渠道公理

nil 频道上的发送将永远阻塞 (Spec: Send statements) 来自nil 频道的接收将永远阻塞 (Spec: Receive operator) 发送到已关闭通道的错误 (Spec: Send statements) 来自关闭通道的接收立即返回零值 (Spec: Receive operator)

nil 通道阻塞的原因:如果通道值为nil,则没有人引用它,所以没有人准备好接收它(我们想要发送的内容);或在其上发送任何内容(我们会从中收到什么)。

你可以在Dave Cheney: Channel Axioms阅读更多的推理和更多细节。

为了完整性:

Closing nil 频道会导致 run-time panic(就像关闭已经关闭的频道一样)。 一个nil频道的Length and capacity是0;根据nil 切片和具有0 长度和容量的映射。

推理:“关闭”是一种状态,但nil 频道不能有状态(nil 频道只有一个,“关闭”和“未关闭”频道没有一个)。并且nil 通道中没有排队的元素(所以 len = 0),并且它没有缓冲区容量(所以 cap = 0)。

【讨论】:

【参考方案2】:

这是预期的行为。发送到nil 频道将永远阻塞。您可以在此处的规格中了解它:https://golang.org/ref/spec#Send_statements

这同样适用于nil 频道上的接收。 (https://golang.org/ref/spec#Receive_operator)

您也可以保留此链接以供参考:http://dave.cheney.net/2014/03/19/channel-axioms

【讨论】:

以上是关于未初始化的通道如何表现?的主要内容,如果未能解决你的问题,请参考以下文章

在通道变量初始化后建立缓冲通道

go 协程

JDBC (未)

如何使用 Pytorch 中的预训练权重修改具有 4 个通道作为输入的 resnet 50?

oracle中 使用exp命令导出数据导出终止失败

如何修复错误“数据库未初始化且未指定密码选项”