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

时间:2015-10-18 09:10:27

标签: go

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

 for f := 1; f <= 1000; f++ {
            if doTest(f) {
              break
            }
  }

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

现在,如何在四个或几个例行程序中正确输入测试数字。基本上,我想测试1到1批次的数字从1到1000(或任何数量的go例程)。 我是否创建了从一个频道读取的4个例程并将数字按顺序输入此频道?或者我使用单个频道制作4个例程?

另一个问题。如果其中一个例程未通过测试,如何停止所有4个例程?我一直在阅读有关频道的文章,但我不能把这些文章放在一起。

2 个答案:

答案 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/