英文:
Closing the channel vs. sending e.g. an empty struct?
问题
我有一个由通道连接的goroutine管道,每个goroutine都会触发另一个,直到所有goroutine都运行完毕。更简单地说,假设有两个goroutine A
和 B
,当 A
完成时,它应该告诉 B
可以运行。
目前它运行得很好,我已经尝试了几种变体,因为我对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的惯用方式来做到这一点?
感谢您对此的任何解释!
英文:
I have a pipeline with goroutines connected by channels so that each goroutine will trigger another one until all have run. Put even simpler, imagine two goroutines A
and B
so that when A
is done it should tell B
it can run.
It's working fine and I have tried a few variants as I have learnt more about pipelines in Go.
Currently I have a signalling channel
ch := make(chan struct{})
go A(ch)
go B(ch)
...
that B
blocks on
func B(ch <-chan struct{}) {
<-ch
...
and A
closes when done
func A(ch chan struct{}) {
defer close(ch)
...
}
This works fine and I also tried, instead of closing, sending an empty struct struct{}
in A()
.
Is there any difference between closing the channel or sending the empty struct? Is either way cheaper / faster / better?
Naturally, sending any other type in the channel takes up "some" amount of memory, but how is it with the empty struct? Close is just part of the channel so not "sent" as such even if information is passed between goroutines.
I'm well aware of premature optimization. This is only to understand things, not to optimize anything.
Maybe there's an idiomatic Go way to do this even?
Thanks for any clarification on this!
答案1
得分: 2
关闭一个通道表示该通道上将不再发送任何消息。通常情况下,这是首选的做法,因为在意外发送或关闭(编程错误)之后,你会得到一个 panic。close
还可以向多个接收者发出信号,表示没有更多的消息,而通过仅发送特殊值来协调这一点就不那么容易。
当然,向通道发送任何其他类型的值都会占用一定的内存,但是空结构体呢?
在无缓冲通道中,并没有保证它会占用任何额外的内存(这完全是实现细节)。发送操作会阻塞,直到接收操作可以继续进行。
关闭只是通道的一部分,即使在 goroutine 之间传递信息,也不会被“发送”。
这里没有优化,close
只是另一种可以发送到通道的消息类型。
每种构造都有明确的含义,你应该使用适当的方式:
- 如果你需要向一个接收者发送特殊值,并保持通道打开以发送更多的值,请发送一个特殊值。
- 如果这是最后一条消息,可能需要向多个接收者发出信号,并且再次发送或关闭将导致错误,请关闭通道。
英文:
closing a channel indicates that there will be no more sends on that channel. It's usually preferable, since you would get a panic after that point in the case of an inadvertent send or close (programming error). A close
also can signal multiple receivers that there are no more messages, which you can't as easily coordinate by just sending sentinel values.
> Naturally, sending any other type in the channel takes up "some" amount of memory, but how is it with the empty struct?
There's no guarantee that it does take any extra memory in an unbuffered channel (it's completely an implementation detail). The send blocks until the receive can proceed.
> Close is just part of the channel so not "sent" as such even if information is passed between goroutines.
There's no optimization here, close
is simply another type of message that can be sent to a channel.
Each construct has a clear meaning, and you should use the appropriate one.
-
Send a sentinel value if you need to signal one receiver, and keep the channel open to send more values.
-
Close the channel if this is the final message, possibly signal multiple receivers, and it would be an error to send or close again.
答案2
得分: 0
你可以通过多个goroutine从关闭的通道接收数据,它们不会被阻塞。这是一个主要的优势。这是一对多模式。
当许多并发的运行程序想要报告任务完成时,可以使用finish := make(chan struct{})
来实现多对一模式,而外部程序不会引发panic
。
这与内存消耗无关。
英文:
You can receive from closed channel by multiple goroutines and they will never block. It's a main advantage. It's one_to_many pattern.
finish := make(chan struct{})
can be used in many_to_one pattern when many concurrent runners want to report things done, and outsider will not panic
.
It's not about memory consumption.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论