将顺序测试分散到 4 个 go 例程中,如果有一个失败则终止所有测试

假设我有一个简单的循环,它执行这样的顺序测试。


 for f := 1; f <= 1000; f++ {

            if doTest(f) {

              break

            }

  }

我遍历数字范围并对每个数字进行测试。如果一个数字的测试失败,我会中断并退出主线程。足够简单。


现在,如何正确地在四个或几个 go 例程中输入测试数字。基本上,我想以 4 为一组(或任何数量的 go 例程)测试从 1 到 1000 的数字。我是否创建 4 个从一个通道读取的例程并将数字按顺序输入该通道?还是我用一个单独的频道做 4 个例程?


还有一个问题。如果其中一个例程未通过测试,我如何停止所有 4 个例程?我一直在阅读频道上的一些文本,但我无法将这些片段放在一起。


开心每一天1111
浏览 173回答 2
2回答

皈依舞

您可以创建一个生产者/消费者系统:https : //play.golang.org/p/rks0gB3aDbfunc main() {&nbsp; &nbsp; ch := make(chan int)&nbsp; &nbsp; clients := 4&nbsp; &nbsp; // make it buffered, so all clients can fail without hanging&nbsp; &nbsp; notifyCh := make(chan struct{}, clients)&nbsp; &nbsp; go produce(100, ch, notifyCh)&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; wg.Add(clients)&nbsp; &nbsp; for i := 0; i < clients; i++ {&nbsp; &nbsp; &nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; consumer(ch, notifyCh)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; }()&nbsp; &nbsp; }&nbsp; &nbsp; wg.Wait()}func consumer(in chan int, notifyCh chan struct{}) {&nbsp; &nbsp; fmt.Printf("Start consumer\n")&nbsp; &nbsp; for i := range in {&nbsp; &nbsp; &nbsp; &nbsp; <-time.After(100 * time.Millisecond)&nbsp; &nbsp; &nbsp; &nbsp; if i == 42 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("%d fails\n", i)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; notifyCh <- struct{}{}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("%d\n", i)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Printf("Consumer stopped working\n")}func produce(N int, out chan int, notifyCh chan struct{}) {&nbsp; &nbsp; for i := 0; i < N; i++ {&nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; case out <- i:&nbsp; &nbsp; &nbsp; &nbsp; case <-notifyCh:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; close(out)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; close(out)}生产者将数字从 0 到 99 推送到通道,消费者一直消费直到通道关闭。在 main 中,我们创建了 4 个客户端并将它们添加到一个等待组中,以可靠地检查每个 goroutine 是否返回。每个消费者都可以在 notifyCh 上发信号,生产者停止工作并且不再产生更多的数字,因此所有消费者都在他们当前的数字之后返回。还有一个选项可以创建4个go例程,等待它们全部返回,开始接下来的4个go例程。但这会增加等待的开销。既然你提到了素数,这里有一个非常酷的素数:https ://golang.org/doc/play/sieve.go

LEATH

您是要为每个例程创建一个公共频道还是一个频道,取决于您想要什么。如果你只想在里面放一些数字(或更一般的 - 请求)并且你不关心哪个 goroutine 提供服务,那么当然最好共享一个频道。例如,如果您希望 goroutine1 为前 250 个请求提供服务,那么您当然不能共享频道。对于通道是一个很好的做法,将其用作输入或输出。发送者如何发送最简单的事情,他完成了关闭通道。关于这一点的好文章是https://blog.golang.org/pipelines问题中没有提到的是 - 您是否还需要另一个通道(或多个通道)或任何其他通信原语来获得结果。这是比喂食更有趣的渠道。应该发送什么信息 - 应该发送它,在每次 doTest 之后发送一个 bool,或者只知道什么时候完成了所有事情(在这种情况下,bool 都不需要只关闭一个通道)?如果你喜欢程序一开始就失败。比我更喜欢使用缓冲共享通道来提供数字。不要忘记关闭它,当所有数字都将被馈送时。另一个无缓冲的 chan 让主线程知道,测试已经完成。它可以是通道,在那里你只输入数字,测试失败的地方,或者如果你还想要一个肯定的结果 - 包含数字和结果的结构通道,或从 doTest 返回的任何其他信息。关于频道的非常好的文章也是http://dave.cheney.net/2014/03/19/channel-axioms您的四个 goroutine 中的每一个都可以报告失败(通过发送错误和关闭通道)。但是当所有数字都通过并且馈送通道关闭时,goroutines 应该做的是gotcha。关于那也是不错的文章http://nathanleclaire.com/blog/2014/02/15/how-to-wait-for-all-goroutines-to-finish-executing-before-continuing/
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go