Go中生产者/消费者最容易理解的成语是什么?

我想做的是拥有一组生产者goroutine(其中一些可能完成或可能不完成)和一个消费者例程。问题在于括号中的警告-我们不知道将返回答案的总数。

所以我想做的是:

package main

import (

"fmt"

"math/rand"

)

func producer(c chan int) {

// May or may not produce.

success := rand.Float32() > 0.5

if success {

c <- rand.Int()

}

}

func main() {

c := make(chan int, 10)

for i := 0; i < 10; i++ {

go producer(c, signal)

}

// If we include a close, then that's WRONG. Chan will be closed

// but a producer will try to write to it. Runtime error.

close(c)

// If we don't close, then that's WRONG. All goroutines will

// deadlock, since the range keyword will look for a close.

for num := range c {

fmt.Printf("Producer produced: %d\n", num)

}

fmt.Println("All done.")

}

所以问题是,如果我关闭它是错误的,如果我没有关闭-它仍然是错误的(请参见代码中的注释)。

现在,解决方案将是一个带外信号通道,所有生产者都将其写入:

package main

import (

"fmt"

"math/rand"

)

func producer(c chan int, signal chan bool) {

success := rand.Float32() > 0.5

if success {

c <- rand.Int()

}

signal <- true

}

func main() {

c := make(chan int, 10)

signal := make(chan bool, 10)

for i := 0; i < 10; i++ {

go producer(c, signal)

}

// This is basically a 'join'.

num_done := 0

for num_done < 10 {

<- signal

num_done++

}

close(c)

for num := range c {

fmt.Printf("Producer produced: %d\n", num)

}

fmt.Println("All done.")

}

这完全可以满足我的需求!但是在我看来,这似乎是满口的。我的问题是:是否有任何习语/技巧可以让我以更简单的方式做类似的事情?

我在这里查看了一下:http :

//golang.org/doc/codewalk/sharemem/

似乎completechan(在开头main)已在一定范围内使用,但从未关闭。我不明白如何。

如果有人有任何见解,我将不胜感激。干杯!


编辑:fls0815有答案,并且还回答了近距离通道范围如何工作的问题。

我上面的代码修改为可以工作(在fls0815之前提供的代码之前完成):

package main

import (

"fmt"

"math/rand"

"sync"

)

var wg_prod sync.WaitGroup

var wg_cons sync.WaitGroup

func producer(c chan int) {

success := rand.Float32() > 0.5

if success {

c <- rand.Int()

}

wg_prod.Done()

}

func main() {

c := make(chan int, 10)

wg_prod.Add(10)

for i := 0; i < 10; i++ {

go producer(c)

}

wg_cons.Add(1)

go func() {

for num := range c {

fmt.Printf("Producer produced: %d\n", num)

}

wg_cons.Done()

} ()

wg_prod.Wait()

close(c)

wg_cons.Wait()

fmt.Println("All done.")

}

回答:

只有生产者应该关闭渠道。您可以通过range在创建生产商之后调用在结果通道上进行迭代()的消费者来实现您的目标。在您的主线程中,您等待(请参阅sync.WaitGroup),直到您的消费者/生产者完成工作为止。生产者完成后,您关闭生成的通道,这将迫使您的消费者退出(range在通道关闭且没有剩余缓冲项目时退出)。

示例代码:

package main

import (

"log"

"sync"

"time"

"math/rand"

"runtime"

)

func consumer() {

defer consumer_wg.Done()

for item := range resultingChannel {

log.Println("Consumed:", item)

}

}

func producer() {

defer producer_wg.Done()

success := rand.Float32() > 0.5

if success {

resultingChannel <- rand.Int()

}

}

var resultingChannel = make(chan int)

var producer_wg sync.WaitGroup

var consumer_wg sync.WaitGroup

func main() {

rand.Seed(time.Now().Unix())

for c := 0; c < runtime.NumCPU(); c++ {

producer_wg.Add(1)

go producer()

}

for c := 0; c < runtime.NumCPU(); c++ {

consumer_wg.Add(1)

go consumer()

}

producer_wg.Wait()

close(resultingChannel)

consumer_wg.Wait()

}

我将close-statement放入主函数的原因是因为我们有多个生产者。在上面的示例中,关闭一个生产者中的通道会导致您已经遇到的问题(在封闭的通道上写;原因是可能还有一位生产者留下来仍在生产数据)。仅当没有生产者时才应关闭通道(因此,我建议仅由生产者关闭通道)。这就是Go中构建通道的方式。在这里,您会找到有关关闭频道的更多信息。


与sharemem示例相关:AFAICS通过一次又一次地对资源进行排队(从挂起->完整->挂起->完整…依次类推),使该示例无休止地运行。这就是main-

func末尾的迭代。它接收完成的资源,并使用Resource.Sleep()将它们重新排队以待处理。当没有完成的资源时,它将等待并阻止新资源完成。因此,由于通道一直在使用中,因此无需关闭通道。

以上是 Go中生产者/消费者最容易理解的成语是什么? 的全部内容, 来源链接: utcz.com/qa/402641.html

回到顶部