问题描述
func (s *server) send(m *message) error {
go func() {
s.outgoingMessageChan <- message
}()
return nil
}
func main(s *server) {
for {
select {
case <-someChannel:
// do something
case msg := <-s.outGoingMessageChan:
// take message sent from "send" and do something
}
}
}
我正在另一个函数中退出此s.outgoingMessageChan
,在使用匿名go函数之前,对该函数的调用通常会阻塞-这意味着无论何时调用send
,s.outgoingMessageChan <- message
都会阻止,直到有东西从里面拉出来。但是,在像这样包装之后,它似乎不再阻塞了。我知道这种操作会将这种操作发送到后台并照常进行,但是我无法解决这不会影响当前函数调用的问题。
解决方法
每次调用send
时,都会创建一个新的goroutine,并立即返回。 (顺便说一句,如果永远都不会发生错误,则没有理由返回错误。)如果没有东西可以从chan
读取(假设它是无缓冲)。从chan
读取消息后,goroutine将继续执行,但是由于它什么也不做,因此只会结束。
我应该指出,没有匿名goroutine 这样的东西。 Goroutine根本没有标识符(除了只能用于调试目的的数字)。您有一个匿名函数,您将go
关键字放在前面,使它在单独的goroutine中运行。
对于发送函数,它可以按您希望的方式阻止,然后只需使用:
func (s *server) send(m *message) {
s.outgoingMessageChan <- message
}
但是,我看不到此函数的任何要点(尽管它是内联的,并且与不使用函数一样有效)。
我怀疑您可能多次打电话给send
,然后才能从chan读取任何内容。在这种情况下,将创建许多新的goroutine(每次调用send
),这些例程将全部阻塞。每次从chan中读取chan都会取消阻止传递其值,并且goroutine将终止。这样做只是在创建效率低下的缓冲机制。此外,如果send
的调用时间延长得比从chan读取的值快,那么您最终将耗尽内存。最好使用一个缓冲通道(不使用goroutines),一旦该通道(通道)变满,它将对产生消息的任何对象施加“背压”。
另一点是,函数名称main
用于标识程序的入口点。请为上面的第二个功能使用其他名称。似乎也应该是方法(使用s *server
接收器)而不是函数。