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?
CodePudding user response:
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
The done
channel is required because consuming does not happen in the main
goroutine, and the main
goroutine must wait for it to end.
If you do the consuming on the main
goroutine, you can remove the done
channel:
msq := NewMessageQueue(10)
go msq.Produce()
msq.Consume(op1)
Try this one on the Go Playground.
CodePudding user response:
The done channel is not buffered
Your program try to send the “true” but there is no goroutine to read it.
Add a size 1, or close this channel when ready