Assuming one goroutine is waiting on the following select on two unbuffered channels one
and two
select {
case <-one:
fmt.Println("read from one")
case <-two:
fmt.Println("read from two")
}
and one one goroutine is waiting on the following send
one <- 1
and another is waiting on the following
two <- 2
The first waiting on a select implies that there is room in the buffer for both the channels one
and two
, then which select
case is guaranteed to run? Is it deterministic or can either run with one channel left with one unread value at the end.
If there is only one guaranteed net output, then do select
s ensure a total order across all operations on all the channels participating in the select
? That seems very inefficient..
For example in the following code
package main
import (
"fmt"
"time"
"sync"
)
func main() {
one_net := 0
two_net := 0
var mtx = &sync.Mutex{}
for i := 0; i < 8; i++ {
one, two := make(chan int), make(chan int)
go func() { // go routine one
select {
case <-one:
fmt.Println("read from one")
mtx.Lock()
one_net++
mtx.Unlock()
case <-two:
fmt.Println("read from two")
mtx.Lock()
two_net++
mtx.Unlock()
}
}()
go func() { // go routine two
one <- 1
mtx.Lock()
one_net--
mtx.Unlock()
fmt.Println("Wrote to one")
}()
go func() { // go routine three
two <- 2
mtx.Lock()
two_net--
mtx.Unlock()
fmt.Println("Wrote to two")
}()
time.Sleep(time.Millisecond)
}
mtx.Lock()
fmt.Println("one_net", one_net)
fmt.Println("two_net", two_net)
mtx.Unlock()
}
can there even be a mismatch in the number of reads vs the number of writes (i.e. can one_net
and two_net
be non 0 at the end)? For example in the case where the select statement is waiting on a read from both channels, and then goroutines two and three go through with their respective writes, but then the select
only picks up on one of those writes.