我是新手,无法找到此问题的答案。我正在做的是在生产者中读取CSV文件,做一些可能需要一些时间的事情,然后通过通道将输出发送给消费者。 生产者-消费者的链条,任何生产者最终都可能比其消费者慢。
producer(1 goroutine)-> chan0-> Consumer-producer-1(> 1 goroutines)-> chan1-> Consumer-producer-2(> 1 goroutines)-> chan2-> Consumer(> 1 goroutines)
这里最多可以有15位消费者。
现在,我面临的问题是如何在消费者方面决定生产者是否完成,而我们可以停止处理。
我需要实现的是:
我使用了以下方法。
下面是我想到的这里。
processRemaining = false
for processRemaining == false{
select {
case stuff, ok := <-input_messages:
do_stuff(stuff)
if ok == false { // if channel has been closed
processRemaining = true
}
if result != nil {
//send to channel output_messages
}
case sig := <-input_signals: // if signaled to stopped.
fmt.Println("received signal", sig)
processRemaining = true
default:
fmt.Println("no activity")
}
}
if processRemaining {
for stuff := range input_messages {
do_stuff(stuff)
if result != nil {
//send to channel output_messages
}
}
// send "output_routine" number of "done" to a channel "output_signals".
}
但是即使采用这种方法,我也无法想出任何方式来表现与关闭的“ input_messages”频道相同的方式,如果在10秒钟之内没有可用的话。
这种方法是否有我忽略的问题。解决此问题的可能方式(或并发模式)是什么?确保:
答案 0 :(得分:0)
使用sync.WaitGroup
跟踪正在运行的goroutine的数量。每个goroutine不再从通道获取数据后退出。 WaitGroup
完成后,即可完成清理。
类似这样的东西:
import (
"sync"
"time"
)
type Data interface{} // just an example
type Consumer interface {
Consume(Data) Data
CleanUp()
Count() int
Timeout() time.Duration
}
func StartConsumers(consumer Consumer, inCh <-chan Data, outCh chan<- Data) {
wg := sync.WaitGroup{}
for i := 0; i < consumer.Count(); i++ {
wg.Add(1)
go func() {
consumeLoop:
for {
select {
case v, ok := <-inCh: // 'ok' says if the channel is still open
if !ok {
break consumeLoop
}
outCh <- consumer.Consume(v)
case <-time.After(consumer.Timeout()):
break consumeLoop
}
}
wg.Done()
}()
}
wg.Wait()
consumer.CleanUp()
close(outCh)
}
在管道的每个阶段,您可以使用与上述类似的过程来启动使用者。