匿名函数中的该例程如何正常工作?

问题描述

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函数之前,对该函数调用通常会阻塞-这意味着无论何时调用sends.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接收器)而不是函数。