I have the go code, that basically runs two go routines concurrently. One of them sends 10 int numbers from (1-10) to the buffered channel "ch"(capacity is 4), and another go routine reads values from channel with the help of for range loop
package main
import (
"fmt"
"sync"
"time"
"runtime"
)
func doSm(ch chan int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 1; i <= 10; i++ {
fmt.Println("sending", i)
ch <- i
fmt.Println("sent", i)
}
close(ch)
}
func doSm2(ch chan int, wg *sync.WaitGroup) {
defer wg.Done()
time.Sleep(5 * time.Second)
for v := range ch {
fmt.Println("result:", v)
}
}
func main() {
runtime.GOMAXPROCS(1)
var wg sync.WaitGroup
ch := make(chan int, 4)
wg.Add(2)
go doSm(ch, &wg)
go doSm2(ch, &wg)
wg.Wait()
}
The issue can be found in the output below.
doSm() sends 4 int through channel and go scheduler blocks the go routine until doSm2() reads those 4 values from channel. After that, the buffer is empty and doSm() sends 1 int, and doSm2() instantly reads it. Now, buffer is empty again and ready to send 4 values. However, doSm() somehow sends 5 values (6, 7, 8, 9, 10) in spite of its capacity.
sending 1
sent 1
sending 2
sent 2
sending 3
sent 3
sending 4
sent 4
sending 5
result: 1
result: 2
result: 3
result: 4
result: 5
sent 5
sending 6
sent 6
sending 7
sent 7
sending 8
sent 8
sending 9
sent 9
sending 10
sent 10
result: 6
result: 7
result: 8
result: 9
result: 10
Any idea why is it happening? Or am I missing something?
An example explanation.
result: 5
sent 5
sending 6
sent 6
sending 7
sent 7
sending 8
sent 8
sending 9
sent 9
sending 10
sent 10
result: 6
result 5
is printed, then we see sent 6-7-8-9-10
, then we see result 6
printed. This does not mean the values 6-7-8-9-10
are all in the channel's buffer (obviously they aren't). The value 6
is already received from the channel, but the subsequent fmt.Println()
line is not yet executed. But since 6
is received, there are only 3 numbers in the buffer and so 10
can be sent on the channel, as can be seen in the output.