【问题标题】:Closing the channel vs. sending e.g. an empty struct?关闭通道与发送例如一个空的结构?
【发布时间】:2015-06-03 20:55:12
【问题描述】:

我有一个管道,其中 goroutine 通过通道连接,因此每个 goroutine 都会触发另一个 goroutine,直到所有 goroutine 都运行完毕。更简单地说,想象两个 goroutines AB 这样当 A 完成时它应该告诉 B 它可以运行。

它运行良好,我尝试了一些变体,因为我对pipelines in Go有了更多了解。

目前我有一个信号通道

ch := make(chan struct{})
go A(ch)
go B(ch)
...

B 阻止

func B(ch <-chan struct{}) {
    <-ch
    ...

A 完成后关闭

func A(ch chan struct{}) {
    defer close(ch)
    ...
}

这很好用,我也尝试过,而不是关闭,而是在 A() 中发送一个空结构 struct{}

关闭通道和发送空结构体有什么区别吗?哪种方式更便宜/更快/更好?

当然,在通道中发送任何其他类型都会占用“一些”内存,但是空结构体又如何呢?关闭只是通道的一部分,因此即使信息在 goroutine 之间传递,也不会“发送”。

我很清楚过早的优化。这只是为了理解事物,而不是优化任何事物。

也许还有一种惯用的 Go 方法可以做到这一点?

感谢您对此的任何澄清!

【问题讨论】:

    标签: go channel goroutine


    【解决方案1】:

    关闭通道表示该通道上将不再有发送。这通常是可取的,因为在无意发送或关闭(编程错误)的情况下,在那之后您会感到恐慌。 close 还可以向多个接收者发出没有更多消息的信号,而您无法通过仅发送标记值来轻松协调。

    当然,在通道中发送任何其他类型都会占用“一些”内存,但是空结构体又如何呢?

    无法保证它确实会在无缓冲通道中占用任何额外的内存(这完全是一个实现细节)。发送阻塞,直到接收可以继续。

    关闭只是通道的一部分,因此即使信息在 goroutine 之间传递,也不会“发送”。

    这里没有优化,close 只是另一种可以发送到频道的消息。

    每个结构都有明确的含义,你应该使用适当的。

    • 如果您需要向一个接收者发送信号,请发送一个哨兵值,并保持通道打开以发送更多值。

    • 如果这是最后一条消息,则关闭通道,可能会向多个接收者发出信号,再次发送或关闭会出错。

    【讨论】:

    • 感谢您的回答。我知道 close 意味着什么,并询问close(ch)ch &lt;- struct{}{}。您是否有一些参考资料表明 close 是一条消息而不是通道的属性?
    • @murrekatt: close 是一个逻辑消息,一个承诺不再发送任何值的特殊值 您认为什么是消息?发送和关闭都只是操纵通道的内部状态,导致将值发送给接收者。
    • 我查看了 Go 源代码,看看 close 做了什么,它设置了一个标志,指示通道已关闭。
    【解决方案2】:

    您可以通过多个 goroutine 从关闭的通道接收,它们永远不会阻塞。这是一个主要优势。这是 one_to_many 模式

    finish := make(chan struct{}) 可以用在 many_to_one 模式中,当许多并发运行者想要报告事情完成时,外人不会panic

    这与内存消耗无关。

    【讨论】:

    • @Uvelichtiel 你不会使用等待组来发出多对一的完成信号吗?
    • @murrekatt 同步等待组用于等待所有人。但是您可以只对获胜者完成感兴趣。在这种情况下,获胜者不应关闭通道,以免外人在关闭的通道上恐慌发送。相反,跑步者应该只向裁判示意他们完成了比赛,然后裁判结束比赛。
    猜你喜欢
    • 1970-01-01
    • 2013-03-20
    • 2021-11-19
    • 1970-01-01
    • 2022-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-05
    相关资源
    最近更新 更多