假设我有一个简单的循环,可以执行这样的顺序测试。
for f := 1; f <= 1000; f++ {
if doTest(f) {
break
}
}
我遍历数字范围并对每个数字进行测试。如果一个数字的测试失败,我会中断并退出主线程。很简单。
现在,如何在四个或几个例行程序中正确输入测试数字。基本上,我想测试1到1批次的数字从1到1000(或任何数量的go例程)。 我是否创建了从一个频道读取的4个例程并将数字按顺序输入此频道?或者我使用单个频道制作4个例程?
另一个问题。如果其中一个例程未通过测试,如何停止所有4个例程?我一直在阅读有关频道的文章,但我不能把这些文章放在一起。
答案 0 :(得分:2)
您可以创建生产者/消费者系统:https://play.golang.org/p/rks0gB3aDb
func main() {
ch := make(chan int)
clients := 4
// make it buffered, so all clients can fail without hanging
notifyCh := make(chan struct{}, clients)
go produce(100, ch, notifyCh)
var wg sync.WaitGroup
wg.Add(clients)
for i := 0; i < clients; i++ {
go func() {
consumer(ch, notifyCh)
wg.Done()
}()
}
wg.Wait()
}
func consumer(in chan int, notifyCh chan struct{}) {
fmt.Printf("Start consumer\n")
for i := range in {
<-time.After(100 * time.Millisecond)
if i == 42 {
fmt.Printf("%d fails\n", i)
notifyCh <- struct{}{}
return
} else {
fmt.Printf("%d\n", i)
}
}
fmt.Printf("Consumer stopped working\n")
}
func produce(N int, out chan int, notifyCh chan struct{}) {
for i := 0; i < N; i++ {
select {
case out <- i:
case <-notifyCh:
close(out)
return
}
}
close(out)
}
制作人将数字从0推送到99到频道,消费者消费直到频道关闭。在main中,我们创建4个客户端并将它们添加到等待组,以可靠地检查每个goroutine是否返回。 每个消费者都可以在notifyCh上发出信号,生产者停止工作,不再生成更多号码,因此所有消费者都会在当前号码后返回。
还可以选择创建4个例程,等待所有人返回,开始接下来的4个例行程序。但这会增加等待的开销。
既然你提到了素数,这里有一个非常酷的素数:https://golang.org/doc/play/sieve.go
答案 1 :(得分:0)
是否要创建一个公共通道或每个例程的通道取决于您的需要。
如果您只想在内部放置一些数字(或更多一般请求),而您不关心哪个goroutine服务,那么当然最好共享一个频道。如果你想要goroutine1提供的第一个250请求,当然你不能共享一个频道。
对于频道来说,将其用作输入或输出是一种很好的做法。发送者可以发送的简单事情,即他完成的是关闭频道。关于这件事的好文章是https://blog.golang.org/pipelines
问题中没有提到 - 您还需要另一个频道(或频道)或任何其他通信原语来获得结果。这是最有趣的渠道,而不是喂养。
应该发送什么信息 - 它应该在每次doTest之后发送,bool,或者只知道何时完成everting(这种情况下,只有关闭一个频道才不需要bool)?
如果你喜欢首先失败的程序。比我更喜欢使用缓冲共享频道来提供数字。当所有号码都被喂食时,别忘了关闭它。
另一个无缓冲的陈让主线程知道,测试完成了。它可以是通道,你只需要输入数字,测试失败的地方,或者你还想要一个正结果 - 包含数字和结果的结构通道,或者从doTest返回的任何其他信息。
关于频道的非常好的文章也是http://dave.cheney.net/2014/03/19/channel-axioms
您的四个goroutine中的每一个都可以报告失败(通过发送错误和关闭频道)。但当所有数字都通过并且喂食渠道关闭时,问题就是goroutines应该做的事情。关于这也是很好的文章http://nathanleclaire.com/blog/2014/02/15/how-to-wait-for-all-goroutines-to-finish-executing-before-continuing/