Tried running the below code(producer & consumer) to understand goroutines and channel in golang (removed package and imports from the code snippet below):
var done = make(chan bool)
var msgs = make(chan int)
func produce() {
for i := 0; i < 10; i++ {
msgs <- i
}
fmt.Println("Before closing channel")
close(msgs)
fmt.Println("Before passing true to done")
done <- true
}
func consume() {
for {
msg := <-msgs
time.Sleep(100 * time.Millisecond)
fmt.Println("Consumer: ", msg)
}
}
func main() {
go produce()
go consume()
<-done
fmt.Println("After calling DONE")
}
source code from: http://www.golangpatterns.info/concurrency/producer-consumer
Below is the output when I run the code
Consumer: 0
Consumer: 1
Consumer: 2
Consumer: 3
Consumer: 4
Consumer: 5
Consumer: 6
Consumer: 7
Consumer: 8
Before closing channel
Before passing true to done
After calling DONE
Based on my understanding with goroutines and channel: When we call produce() and consume() from main() using the go keyword, go runtime kicks of 2 goroutines(sort of threads in java world but not actual OS threads) and the main() goroutine comes and halts at "<-done". Now inside produce() - the loop goes from 0 to 9 and inside the loop the msgs channel receives the int (0 to 9) 1 at a time which is being consumed in parallel by the consume(); however produce has no clue about it and it just keep looping for 0 to 9.
Question: Assuming my above understanding is correct. Once, the for loop is done why is the next printLine inside produce() not getting printed and also why is the msgs channel not getting closed? Why is the goroutine halting inside the produce() until the consumer consumes all the msgs?
The msgs
channel is unbuffered. This means that for send to complete, there has to be a corresponding receive operation that can also complete. This provides a synchronization point between goroutines.
It's easy to see if you just add a few more print statements to your example
http://play.golang.org/p/diYQGN-iwE
func produce() {
for i := 0; i < 4; i++ {
fmt.Println("sending")
msgs <- i
fmt.Println("sent")
}
fmt.Println("Before closing channel")
close(msgs)
fmt.Println("Before passing true to done")
done <- true
}
func consume() {
for msg := range msgs {
fmt.Println("Consumer: ", msg)
time.Sleep(100 * time.Millisecond)
}
}
Output:
sending
Consumer: 0
sent
sending
Consumer: 1
sent
sending
Consumer: 2
sent
sending
Consumer: 3
sent
Before closing channel
Before passing true to done
After calling DONE
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With