即使没有竞态条件,也没有得到任何输出。

huangapple go评论108阅读模式
英文:

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 &quot;fmt&quot;

type MessageQueue struct {
	storage chan int
	count   int
}

var done = make(chan bool)

func NewMessageQueue(count int) *MessageQueue {
	ret := &amp;MessageQueue{
		count:   count,
		storage: make(chan int, count),
	}
	return ret
}

func (m *MessageQueue) Produce() {
	for i := 0; i &lt; m.count; i++ {
		m.storage &lt;- i + 1
	}
	done &lt;- true
}

func (m *MessageQueue) Consume(f func(int) int) {
	for each := range m.storage {
		fmt.Printf(&quot;%d &quot;, f(each))
	}
}

func main() {
	op1 := func(a int) int {
		return a * a
	}
	msq := NewMessageQueue(10)
	go msq.Produce()
	go msq.Consume(op1)
	&lt;-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 &lt; m.count; i++ {
		m.storage &lt;- i + 1
	}
	close(m.storage)
}

func (m *MessageQueue) Consume(f func(int) int) {
	for each := range m.storage {
		fmt.Printf(&quot;%d &quot;, f(each))
	}
	done &lt;- 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.

huangapple
  • 本文由 发表于 2022年3月22日 16:41:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/71569119.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定