fmt.Println is not executing in order when used without sleep

Viewed 41

I'm trying to understand, why my code doesn't behave as I expect it. The problem is that I would expect, that my code would behave like that:

  1. Define channel
  2. Run goroutine and start looping
  3. Put value into channel, print "finished"
  4. Starting second iteration, blocking call(there is already value in the channel), move to main goroutine
  5. Printing 1, trying to run second iteration, blocking call for main goroutine, coming back to second goroutine
  6. Cycle repeats

It works like that, but only with time.Sleep, but for some reason when commenting out time.Sleep it behaves totally different. What's even more interesting that sometimes for really small values of time like Nanos etc this code returns even more different results. Could someone explain me, why it works like that? My guess is that maybe Println is too slow on display, but it sounds weird to me..

Thanks

** As expected: **

finished
1
finished
2
finished
3
finished
6
finished
4
finished
8
finished all

** Not expected **

finished
1
2
finished
finished
3
finished
6
4
finished
finished
8
finished all
func main() {
    var c chan int = make(chan int)
    go sendingThrowingResults(c)

    for val := range c {
        fmt.Println(val)
    }

    fmt.Println("finished all")
}

func sendingThrowingResults(c chan int) {
    var results []int = []int{1, 2, 3, 6, 4, 8}

    for _, val := range results {
        //time.Sleep(100 * time.Millisecond)
        c <- val
        fmt.Println("finished")
    }
    defer close(c)
}
1 Answers

A channel operation needs both sides to participate. A write only happens when a reader is ready. Once that happens, there is no guarantee on which goroutine will run first.

Thus, once the channel write happens, one of the two printlns will work, in some random order.

Related