首页 > 解决方案 > 从 go 通道流中读取

问题描述

我试图理解从通道通道读取的以下代码。我在思考这个想法时遇到了一些困难。

    bridge := func(done <-chan interface{}, chanStream <-chan <-chan interface{}) <-chan interface{} {
        outStream := make(chan interface{})
        go func() {
            defer close(outStream)
            for {
                var stream <-chan interface{}
                select {
                case <-done:
                    return
                case maybeSteram, ok := <-chanStream:
                    if ok == false {
                        return
                    }
                    stream = maybeSteram
                }
                for c := range orDone(done, stream) {
                    select {
                    case outStream <- c:
                    case <-done:  // Why we are selection from the done channel here?
                    }
                }
            }
        }()
        return outStream
    }

orDone功能:

    orDone := func(done <-chan interface{}, inStream <-chan interface{}) <-chan interface{} {
        outStream := make(chan interface{})
        go func() {
            defer close(outStream)
            for {
                select {
                case <-done:
                    return
                case v, ok := <-inStream:
                    if ok == false {
                        return
                    }
                    select {
                    case outStream <- v:
                    case <-done:  // Again why we are only reading from this channel? Shouldn't we return from here?
                        // Why we are not retuening from here?
                    }
                }
            }
        }()
        return outStream
    }

正如评论中提到的,我需要一些帮助来理解我们为什么选择for c := range orDone(donem, stream). 谁能解释这里发生了什么?

提前致谢。

编辑

我从书中拿了代码concurrency in go。完整的代码可以在这里找到:https ://github.com/kat-co/concurrency-in-go-src/blob/master/concurrency-patterns-in-go/the-bridge-channel/fig-bridge-频道.go

标签: gochannel

解决方案


在这两种情况下,选择都是为了避免阻塞——如果读取器没有从我们的输出通道读取,写入可能会阻塞(甚至可能永远阻塞),但是我们希望 goroutine 在done通道关闭时终止,而无需等待还要别的吗。通过使用select,它将等到任何事情发生,然后继续,而不是在检查之前无限期地等待写入完成done

至于另一个问题,“我们为什么不回到这里?”:嗯,我们可以。但我们不必这样做因为关闭的通道一旦关闭就永远保持可读(产生无限数量的零值)。所以在那些“底层”什么都不做也没关系selects;如果done实际上是关闭的,我们将回到循环的顶部并点击case <-done: return那里。我想这是风格问题。我可能会自己编写return,但此示例的作者可能希望避免在两个地方处理相同的情况。只要它只是return它并不重要,但如果你想对它做一些额外的操作done,如果底部选择返回,则必须在两个地方更新该行为,但如果没有,则只在一个地方更新。


推荐阅读