scheduling of goroutines
About
I was debugging some program and was curious about a race condition. The program has a buffered channel of size N, and a goroutine is sending N+1 messages.
If I read a message in the main thread, why is the length of the buffer still N?
package main
import "fmt"
func main() {
ch := make(chan int, 1)
go func() {
ch <- 0
ch <- 0
}()
<-ch
n := len(ch)
fmt.Println(n)
}Experiment
A search on the internet hinted at the non-deterministic behavior of scheduling goroutines.
In order to confirm the non-deterministic behavior, I ran 1 million go routines and printed the results.
package main
import (
"fmt"
"os"
"sync"
"text/tabwriter"
)
func run(update chan int, wg *sync.WaitGroup) {
ch := make(chan int, 1)
go func() {
ch <- 0
ch <- 0
}()
<-ch
update <- len(ch)
wg.Done()
}
func main() {
var wg sync.WaitGroup
update := make(chan int)
result := make(map[int]int)
w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
go func() {
for {
v := <-update
result[v] = result[v] + 1
}
}()
for range 1_000_000 {
wg.Add(1)
go run(update, &wg)
}
wg.Wait()
fmt.Fprintf(w, "0\t1\n")
fmt.Fprintf(w, "%d\t%d\n", result[0], result[1])
w.Flush()
}In the 1 million experiments that ran, only 12 executions resulted in a buffer of length N-1 while the rest had lengths of N:
0 1
12 999988