donglanying3855 2019-08-04 05:34
浏览 70
已采纳

从Go频道流中阅读

I was trying to understand the following piece of code that reads from a channel of channels. I am having some difficulties wrapping my head around the idea.

    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
    }

The orDone function:

    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
    }

As mentioned in the comment, I need some help to understand why we are selecting in the for c := range orDone(donem, stream). Can anyone explain what is going on here?

Thanks in advance.

Edit

I took the code from the book concurrency in go. The full code can be found here: https://github.com/kat-co/concurrency-in-go-src/blob/master/concurrency-patterns-in-go/the-bridge-channel/fig-bridge-channel.go

  • 写回答

2条回答 默认 最新

  • dsa89029 2019-08-04 05:59
    关注

    In both cases, the select is done to avoid blocking — if the reader isn't reading from our output channel, the write might block (maybe even forever), but we want the goroutine to terminate when the done channel is closed, without waiting for anything else. By using the select, it will wait until either thing happens, and then continue, instead of waiting indefinitely for the write to complete before checking done.

    As for the other question, "why are we not returning here?": well, we could. But we don't have to, because a closed channel remains readable forever (producing an unlimited number of zero values) once it's been closed. So it's okay to do nothing in those "bottom" selects; if done was in fact closed we will go back up to the top of the loop and hit the case <-done: return there. I suppose it's a matter of style. I probably would have written the return myself, but the author of this sample may have wanted to avoid handling the same condition in two places. As long as it's just return it doesn't really matter, but if you wanted to do some additional action on done, that behavior would have to be updated in two places if the bottom select returns, but only in one place if it doesn't.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 拟通过pc下指令到安卓系统,如果追求响应速度,尽可能无延迟,是不是用安卓模拟器会优于实体的安卓手机?如果是,可以快多少毫秒?
  • ¥20 神经网络Sequential name=sequential, built=False
  • ¥16 Qphython 用xlrd读取excel报错
  • ¥15 单片机学习顺序问题!!
  • ¥15 ikuai客户端多拨vpn,重启总是有个别重拨不上
  • ¥20 关于#anlogic#sdram#的问题,如何解决?(关键词-performance)
  • ¥15 相敏解调 matlab
  • ¥15 求lingo代码和思路
  • ¥15 公交车和无人机协同运输
  • ¥15 stm32代码移植没反应