I am trying to create producer-consumer message queue system in Golang using buffered channel. Here is my implementation.
package main
import "fmt"
type MessageQueue struct {
storage chan int
count int
}
var done = make(chan bool)
func NewMessageQueue(count int) *MessageQueue {
ret := &MessageQueue{
count: count,
storage: make(chan int, count),
}
return ret
}
func (m *MessageQueue) Produce() {
for i := 0; i < m.count; i++ {
m.storage <- i + 1
}
done <- true
}
func (m *MessageQueue) Consume(f func(int) int) {
for each := range m.storage {
fmt.Printf("%d ", f(each))
}
}
func main() {
op1 := func(a int) int {
return a * a
}
msq := NewMessageQueue(10)
go msq.Produce()
go msq.Consume(op1)
<-done
}
But unfortunately, I am not able to get the output when I run go run main.go however to check if there is any race condition or not, when I try go run -race main.go, I do get the output. I am unable to understand why it is happening. Can anyone help me here?
>Solution :
When your producer can send the values, it sends a value on the done channel so your app can terminate immediately.
Instead when the producer is done, it should close the m.storage channel, signalling no more values will be sent, and do not send a value on done, as you’re not done!
You’re done when values are consumed, so send a value on done in Consume():
func (m *MessageQueue) Produce() {
for i := 0; i < m.count; i++ {
m.storage <- i + 1
}
close(m.storage)
}
func (m *MessageQueue) Consume(f func(int) int) {
for each := range m.storage {
fmt.Printf("%d ", f(each))
}
done <- true
}
This will output (try it on the Go Playground):
1 4 9 16 25 36 49 64 81 100