Reading from a goroutine channel without blocking

Issue

I have two goroutines: the main worker and a helper that it spins off for some help. helper can encounter errors, so I use a channel to communicate errors over from the helper to the worker.

func helper(c chan <- error) (){
    //do some work
    c <- err // send errors/nil on c
}

Here is how helper() is called:

func worker() error {
    //do some work
    c := make(chan error, 1)
    go helper(c)
    err := <- c
    return err
}

Questions:

  • Is the statement err := <- c blocking worker? I don’t think so, since the channel is buffered.

  • If it is blocking, how do I make it non-blocking? My requirement is to have worker and its caller continue with rest of the work, without waiting for the value to appear on the channel.

Thanks.

Solution

You can easily verify

func helper(c chan<- error) {
    time.Sleep(5 * time.Second)
    c <- errors.New("") // send errors/nil on c
}

func worker() error {
    fmt.Println("do one")

    c := make(chan error, 1)
    go helper(c)

    err := <-c
    fmt.Println("do two")

    return err
}

func main() {
    worker()
}

Q: Is the statement err := <- c blocking worker? I don’t think so, since the channel is buffered.

A: err := <- c will block worker.

Q: If it is blocking, how do I make it non-blocking? My requirement is to have worker and its caller continue with rest of the work, without waiting for the value to appear on the channel.

A: If you don’t want blocking, just remove err := <-c. If you need err at the end, just move err := <-c to the end.

You can not read channel without blocking, if you go through without blocking, can can no more exec this code, unless your code is in a loop.

Loop:
    for {
        select {
        case <-c:
            break Loop
        default:
            //default will go through without blocking
        }
        // do something
    }

And have you ever seen errgroup or waitgroup?

It use atomic, cancel context and sync.Once to implement this.

https://github.com/golang/sync/blob/master/errgroup/errgroup.go

https://github.com/golang/go/blob/master/src/sync/waitgroup.go

Or you can just use it, go you func and then wait for error in any place you want.

Answered By – Sangria

Answer Checked By – Marie Seifert (GoLangFix Admin)

Leave a Reply

Your email address will not be published.