-3

I learn buffered channels in Go and some magic is hidden from me. I have this code

package main

import (
    "fmt"
)

func write(ch chan int) {
    for i := 1; i <= 5; i++ {
        ch <- i
        fmt.Printf("Channel's length is %d\n", len(ch))
    }
    close(ch)
}
func main() {
    ch := make(chan int, 2)
    go write(ch)

    for v := range ch {
        fmt.Println(v)
    }
}

The output is

Channel's length is 0
Channel's length is 1
Channel's length is 2
1
2
3
4
Channel's length is 2
Channel's length is 0
5

Why is the channel's length on the first iteration in write goroutine is zero? What do I don't know?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Dimitry
  • 359
  • 4
  • 13
  • 6
    You have 2 concurrent goroutines, one (the `main`) is receiving values from the channel, so whatever you "put" in that channel may be out of it immediately. There's some "time" between sending on your channel and getting its length. During this time it's not guaranteed that the channel is not touched. – icza Sep 17 '19 at 13:45
  • Shouldn't the write goroutine be active until buffered channel is full? – Dimitry Sep 17 '19 at 13:48
  • 4
    No. They're running *concurrently*. You should assume, conceptually, that they are both active at the same time - that's the definition of "concurrent". – Adrian Sep 17 '19 at 13:50

1 Answers1

2

As per the concept of GO buffer, you can push elements in channels as per defined buffer size (in your case it is 2). But at the time an element is pushed into channel, same is being read by the main GO routine which leads to a decrease in the size of channel to zero. So, if you put some time.Sleep before your read statement you will get the expected result.

`

package main
import (
    "fmt"
    "time"
)

func write(ch chan int) {
    for i := 1; i <= 5; i++ {
        ch <- i
        fmt.Printf("Channel's length is %d\n", len(ch))
    }
    close(ch)
}
func main() {
    ch := make(chan int, 2)
    go write(ch)
    time.Sleep(2*time.Second)
    for v := range ch {
        fmt.Println(v)
        time.Sleep(2*time.Second)
    }
}`

Output for the above code is:

Channel's length is 1

Channel's length is 2

1

Channel's length is 2

2

Channel's length is 2

3

Channel's length is 2

4

5

Community
  • 1
  • 1