为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
开心每一天1111 2021-11-15 17:04:52
假设我有一个简单的循环,它执行这样的顺序测试。 for f := 1; f <= 1000; f++ {            if doTest(f) {              break            }  }我遍历数字范围并对每个数字进行测试。如果一个数字的测试失败,我会中断并退出主线程。足够简单。现在,如何正确地在四个或几个 go 例程中输入测试数字。基本上,我想以 4 为一组(或任何数量的 go 例程)测试从 1 到 1000 的数字。我是否创建 4 个从一个通道读取的例程并将数字按顺序输入该通道?还是我用一个单独的频道做 4 个例程?还有一个问题。如果其中一个例程未通过测试,我如何停止所有 4 个例程?我一直在阅读频道上的一些文本,但我无法将这些片段放在一起。
查看完整描述

2 回答

?
皈依舞

TA贡献1851条经验 获得超3个赞

您可以创建一个生产者/消费者系统: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个go例程,等待它们全部返回,开始接下来的4个go例程。但这会增加等待的开销。


既然你提到了素数,这里有一个非常酷的素数:https ://golang.org/doc/play/sieve.go


查看完整回答
反对 回复 2021-11-15
?
LEATH

TA贡献1936条经验 获得超6个赞

您是要为每个例程创建一个公共频道还是一个频道,取决于您想要什么。

如果你只想在里面放一些数字(或更一般的 - 请求)并且你不关心哪个 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/


查看完整回答
反对 回复 2021-11-15
  • 2 回答
  • 0 关注
  • 172 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信