Home > front end >  Go channel write ordering guarantees
Go channel write ordering guarantees

Time:10-06

Given the following code:

ch1 := make(chan struct{}, 1)
ch2 := make(chan struct{})
ready := make(chan struct{})
done := make(chan struct{})

go func() {
    close(ready)
    select {
    case <-ch1:
        fmt.Println("ch1")
    case <-ch2:
        fmr.Println("ch2")
    }
}()

<-ready

ch1 <- struct{}{}
close(ch2)

<-done

Is it guaranteed to always print "ch1"? Or is it possible that since the ch1 is buffered and ch2 is closed right after, the second case could run first?

And is there any reference to verify this behavior in the documentation / code?

CodePudding user response:

Writing to ch1 will not immediately cause the select operation to continue. The goroutine can be scheduled after the channel write or after the close operation so both cases have a chance to run. If ch1 was unbuffered then write operation would only happen after channel read so the program would always print ch1.

CodePudding user response:

No, there is no guarantee that the second case may not occur.

While you are using channels - and channels are ideal for synchronizing two goroutines - you are manipulating two separate channels. So there is no guarantee that the main goroutine's write to an unbuffered ch1 channel will immediately yield control over to the second goroutine's select statement.

The close of ch2 may also occur before the scheduler yields control to other goroutines - and then a select with two possible paths, will be chosen at random.

Anectodal evidence may be tempting to believe, but will lead to dangerous assumptions under different load conditions.


Looking at an early doc for the Go Scheduler Design doc will not be of much help as the implementation details of the schedule will literally change from release to release of the Go language.

In closing, coordination between the two independent channels is needed to make any guarantees of the processing order.

  • Related