Experimenting with Golang, I have created a function with a select statement that listens to two channels.
My problem is that the code seems to behave non-deterministically - sometimes it panics and sometimes it completes successfully.
My expectation is that this code should always panic. It should receive the error first, because it should be dispatched before the waitGroup has finished and therefore before the success channel is pushed to.
package main
import (
"errors"
"fmt"
"sync"
)
func main() {
errs := make(chan error, 1)
success := make(chan bool, 1)
doSomething(success, errs)
select {
case err := <-errs:
fmt.Println("error", err)
panic(err)
case <-success:
fmt.Println("success")
}
fmt.Println("finished successfully")
}
func doSomething(success chan bool, errs chan error) {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
err := errors.New("Some error")
errs <- err
}()
wg.Wait()
success <- true
}
Both channels are ready before the select statement; so it will chose via a uniform pseudo-random selection:
Let's replace the doSomething
function call in your code, and put defer at the end of the function:
package main
import (
"errors"
"fmt"
"sync"
)
func main() {
errs := make(chan error, 1)
success := make(chan bool, 1)
var wg sync.WaitGroup
wg.Add(1)
go func() {
err := errors.New("some error")
errs <- err
wg.Done()
}()
wg.Wait()
success <- true
select {
case err := <-errs:
fmt.Println("error", err)
panic(err)
case <-success:
fmt.Println("success")
}
fmt.Println("finished successfully")
}
As you see in the above code sample, the main goroutine waits at the wg.Wait()
for the wg.Done()
at this point in time the code is (almost) functionally equal to the following code, and both channels are ready before the select statement here:
package main
import (
"errors"
"fmt"
)
func main() {
errs := make(chan error, 1)
success := make(chan bool, 1)
errs <- errors.New("some error")
success <- true
select {
case err := <-errs:
fmt.Println(err)
case <-success:
fmt.Println("success")
}
}
Run:
$ go run .
some error
$ go run .
success
Select_statements:
If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection. Otherwise, if there is a default case, that case is chosen. If there is no default case, the "select" statement blocks until at least one of the communications can proceed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With