Laird Nelson
Laird Nelson

Reputation: 16174

In a Go case statement featuring channels, where does the blocking happen?

I am a Go rookie.

I'm looking at this construct:

for {
    select {
        case <-resyncCh:
        case <-stopCh:
            return
        case <-cancelCh:
            return
    }
    if r.ShouldResync == nil || r.ShouldResync() {
        // do stuff
    }
    resyncCh = r.resyncChan()
}

Suppose resyncCh does not have a message on it.

Are all the cases evaluated (blocked on) in parallel? Or is there another path through this I'm not seeing?

I read this as:

Is that correct?

Upvotes: 2

Views: 2147

Answers (2)

EdH
EdH

Reputation: 3293

In direct answer to your questions:

  • Block on the resyncCh, the stopCh and the cancelCh chans in parallel waiting for messages. YES.

  • If a message is received on resyncCh, we effectively fall through to the r.ShouldResync stuff, but the other blocks on the other chans remain. No, they don't remain, you are past the select However, since this loops, you will block again. You could also use the fallthrough keyword to make them block after passing the initial one.

  • If a message is received at any point on either the stopCh or the cancelCh chan, return, effectively "disconnecting" from all chans here. Correct - they would return from this function.

Also, bear in mind what you can do with a default --> https://gobyexample.com/non-blocking-channel-operations

for {
    select {
        case <-resyncCh:
        case <-stopCh:
            return
        case <-cancelCh:
            return
        default:
            fmt.Printf("will keep printing\n")
    }
    if r.ShouldResync == nil || r.ShouldResync() {
        // do stuff
    }
    resyncCh = r.resyncChan()
}

update: Another useful pattern, I'm using right now, which takes advantage of this:

select {
case m := <-c:
        handle(m)
case <-time.After(5 * time.Minute):
        fmt.Println("timed out")
}

Here you can wait, blocking, on a channel, but eventually timeout, just using the golang time package. Very succinct and easy to read. Compare that to poll() with timespec values. https://golang.org/pkg/time/#After

Upvotes: 2

Eugene Lisitsky
Eugene Lisitsky

Reputation: 12845

select takes first not blocked action and goes to next operation.

Block on the resyncCh, the stopCh and the cancelCh chans in parallel waiting for messages

Yes, waiting for first of them.

If a message is received on resyncCh, we effectively fall through to the r.ShouldResync stuff, but the other blocks on the other chans remain.

Unlike in some other languages fallthrough is explicit in go - you should state it.

If a message is received at any point on either the stopCh or the cancelCh chan, return, effectively "disconnecting" from all chans here.

Exit from the function where the code located. Yes, we do not wait for new messages more.

Upvotes: 1

Related Questions