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
blockingworker
? 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.
CodePudding user response:
In your code, the rest of the work is independent of whether the helper encountered an error. You can simply receive from the channel after the rest of the work is completed.
func worker() error {
//do some work
c := make(chan error, 1)
go helper(c)
//do rest of the work
return <-c
}
CodePudding user response:
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:
//defalut 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.