英文:
Not getting any output even if there is no race conditions
问题
我正在尝试使用缓冲通道在Golang中创建生产者-消费者消息队列系统。以下是我的实现代码:
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
}
但不幸的是,当我运行go run main.go
时,无法获得输出。然而,当我尝试运行go run -race main.go
来检查是否存在竞态条件时,我确实能够获得输出。我无法理解为什么会发生这种情况。有人可以帮助我吗?
英文:
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?
答案1
得分: 5
当你的生产者可以发送值时,它会在done
通道上发送一个值,以便你的应用程序可以立即终止。
相反,当生产者完成时,它应该关闭m.storage
通道,表示不会再发送更多的值,并且不要在done
上发送一个值,因为你还没有完成!
当值被消耗时,你才完成,所以在Consume()
函数中在done
上发送一个值:
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
}
这将输出(在Go Playground上尝试):
1 4 9 16 25 36 49 64 81 100
done
通道是必需的,因为消费不是在main
goroutine中进行的,而main
goroutine必须等待它结束。
如果你在main
goroutine中进行消费,可以删除done
通道:
msq := NewMessageQueue(10)
go msq.Produce()
msq.Consume(op1)
在Go Playground上尝试这个。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论