Search code examples
goconcurrencychannel

or-done-channel pattern in Go - why no return inside inner select and what happens if both done and producer channel are available?


Reading Concurrency in Go.

Trying to understand the or-done-channel pattern.

Having trouble wrapping my head around the execution flow.

I have mentioned number against the line where my doubt is from.

  1. Why no return statement in inner <-done like we have in outer select? Because of no return statement, the next iteration will run and what if in that iteration we have both <- done and <-c available. We know select-case will choose any of the case arbitrarily if multiple cases are available. Does this mean there is a possibility that <-c will run even if <-done was available?

  2. Since select-case arbitrarily chooses a case when multiple case are available, is it correct to assume that the <- done will be chosen eventually but it is not necessary that it is chosen immediately as soon as it is closed. Of Course, this doubt is when both case i.e. <-done and <-c were available.

  3. There is a possibility that <- v is not written onto valStream when done is closed and it is lost forever, correct?

orDone := func(done, c <-chan interface{}) <-chan interface{} {
    valStream := make(chan interface{})
    go func() {
        defer close(valStream)
        for {
            select {                   //2
            case <-done:
                return
            case v, ok := <-c:
                if ok == false {
                    return
                }
                select {
                case valStream <- v:   //3
                case <-done:           //1
                }
            }
        }
    }()
    return valStream
}

enter image description here

Basically, either correct me if I'm wrong or confirm that my understanding of the execution is correct. There indeed are "loopholes" with the code and that is just channel behaviour here.

Similar Question here


Solution

    1. Inner select <-done case should also have a return. This code is relying on the outer select to capture <-done, which may not happen immediately
    2. If <-done is available it will be chosen eventually. It is likely that it will be chosen quickly, but you are correct. There is no guarantee that even if the inner select chooses <-done, the outer will chose it as well in its next iteration.
    3. If <-done is available, then yes, there is a possibility that v will be read but won't be written