如何通知golang中的频道发送者退出?

时间:2014-12-16 02:22:39

标签: go channel

我在Go中使用通道来处理各种数据管道。代码看起来像这样:

type Channels struct {
    inputs chan string
    errc   chan error
    quit   chan struct{}
}

func (c *Channels) doSomethingWithInput() {
    defer close(c.quit)
    defer close(c.errc)
    for input := range p.inputs {
        _, err := doSomethingThatSometimesErrors(input)
        if err != nil {
            c.errc <- err
            return
        }
    }
    doOneFinalThingThatCannotError()
    return
}

func (c *Channels) inputData(s string) {
        // This function implementation is my question
}

func StartProcessing(c *Channels, data ...string) error {
    go c.doSomethingWithInput()
    go func() {
        defer close(c.inputs)
        for _, i := range data {
            select {
            case <-c.quit:
                break
            default:
            }
            inputData(i)
            }
    }()
    // Block until the quit channel is closed.
    <-c.quit
    if err := <-c.errc; err != nil {
        return err
    }
    return nil
}

这似乎是在通道处理器之间传递退出信号的合理方式,并且基于this blog post关于Go中的并发模式。

我使用这种模式所困扰的是inputData函数。向input频道添加字符串需要等待doSomethingWithInput()才能读取频道,但也可能出错。 inputData需要尝试提供inputs频道,但如果被告知退出则放弃。我能做的最好的就是:

func (c *Channels) inputData(s string) {
    for {
        select {
        case <-c.quit:
            return
        case c.inputs <- s:
            return
        }
    }
}

基本上,“在你的选择之间摇摆,直到其中一个坚持。”要清楚,我不认为这是一个糟糕的设计。感觉......浪费。就像我错过了一些聪明的东西。当渠道消费者出错时,如何告诉渠道发件人退出Go?

1 个答案:

答案 0 :(得分:2)

你的inputData()很好,这就是你的方法。

在您的用例中,您的频道消费者,接收者,又名doSomethingWithInput()是应该控制&#34;退出&#34;渠道。实际上,如果发生错误,只需从doSomethingWithInput()返回,这将依次关闭退出通道并使发送者退出(将触发case <-quit:)。事实上这就是聪明的一点。

当doSomethingWithInput()退出时,请注意您的错误频道没有缓冲和关闭。之后您无法读取它以收集错误。您需要在主函数中关闭它并使用一些容量(例如make(chan int, 10))初始化它,或者为它创建一个消费者goroutine。您可能还希望尝试使用select语句读取它:如果没有错误,您的错误检查代码将会永远阻止。