I am a newbie in golang and trying to experiment buffered channels with goroutines. I thought I understood how buffered channels work with goroutines until encountered the below example which becomes a brain teaser for me and gave a bang to the concepts that I have learned so far.
This is the original example that I took from the article https://medium.com/rungo/anatomy-of-channels-in-go-concurrency-in-go-1ec336086adb.
Code#1: (channel capacity=3, channel length=3, loop length=4)
func squares(c chan int) {
for i := 0; i <= 3; i++ {
num := <-c
fmt.Println(num * num)
}
}
func main() {
fmt.Println("main() started")
c := make(chan int, 3)
go squares(c)
c <- 1
c <- 2
c <- 3
fmt.Println("main() stopped")
}
Output:
main() started
main() stopped
Explanation: In the above program, channel c has a buffer capacity of 3. That means it can hold 3 values. Since the buffer is not overflowing (as we didn’t push any new value), the main goroutine will not block and the program exists. I have understood this example.
Code#2: (channel capacity=3, channel length=4, loop length=4)
func squares(c chan int) {
for i := 0; i <= 3; i++ {
num := <-c
fmt.Println(num * num)
}
}
func main() {
fmt.Println("main() started")
c := make(chan int, 3)
go squares(c)
c <- 1
c <- 2
c <- 3
c <- 4 // goroutine blocks here
fmt.Println("main() stopped")
}
Output:
main() started
1
4
9
16
main() stopped
Explanation: As now a filled buffer gets the push by c <- 4 send operation, main goroutine blocks and squares goroutine drains out all the values. It is also understood by me.
Code#3: (channel capacity=3, channel length=5, loop length=5)
func squares(c chan int) {
for i := 0; i <= 4; i++ {
num := <-c
fmt.Println(num * num)
}
}
func main() {
fmt.Println("main() started")
c := make(chan int, 3)
go squares(c)
c <- 1
c <- 2
c <- 3
c <- 4 // goroutine blocks here
c <- 5
fmt.Println("main() stopped")
}
Output:
main() started
1
4
9
16
25
main() stopped
Explanation: I have added another value to the channel which is 5. Although the channel capacity is only 3.
I understand that until the channel receives n+1 send operations, it won’t block the current goroutine. On the value 4, it receives n+1 operations, that's why goroutine gets blocked and drains out all the values but what I am unable to understand is that how n+2 operations are dealt by channel. Is it because we have read the values from the channel and we have more space for reading?