简体   繁体   English

没有通道的 golang errgroup 示例

[英]golang errgroup example without channels

I saw the example of errgroup in godoc, and it makes me confused that it simply assigns the result to global results instead of using channels in each search routines.我在 godoc 中看到了 errgroup 的例子,它只是将结果分配给全局结果而不是在每个搜索例程中使用通道,这让我感到困惑。 Heres the code:代码如下:

Google := func(ctx context.Context, query string) ([]Result, error) {
g, ctx := errgroup.WithContext(ctx)

searches := []Search{Web, Image, Video}
results := make([]Result, len(searches))
for i, search := range searches {
    i, search := i, search // https://golang.org/doc/faq#closures_and_goroutines
    g.Go(func() error {
        result, err := search(ctx, query)
        if err == nil {
            results[i] = result
        }
        return err
    })
}
if err := g.Wait(); err != nil {
    return nil, err
}
return results, nil

} }

I'm not sure is there any reason or implied rules guarantees it is correct?我不确定是否有任何理由或隐含规则保证它是正确的? THX谢谢

The intent here is to make searches and results congruent.这里的目的是使searchesresults一致。 The result for the Web search is always at results[0] , the result for the Image search always at results[1] , etc. It also makes for a simpler example, because there is no need for an additional goroutine that consumes a channel. Web搜索的results[0]总是在results[0]Image搜索的results[1]总是在results[1]等等。这也是一个更简单的例子,因为不需要额外的 goroutine 来消耗一个通道.

If the goroutines would send their results into a channel, the result order would be unpredictable.如果 goroutine 将它们的结果发送到通道,结果顺序将是不可预测的。 If predictable result order is not a property you care about feel free to use a channel.如果可预测的结果顺序不是您关心的属性,请随意使用通道。

There is secret sauce in this code that creates siloing:这段代码中有一个秘密武器可以创建孤岛:

results := make([]Result, len(searches))
           ^^^^           ^^^^^^^^^^^^^

for i, search := ... {
    i, search := i, search
          ^^^^^^^^^^
    g.Go {
        results[i] = result
        ^^^^^^^^^^
    }

We know how big the result set is going to be, so we pre-allocate all the slots before starting any goroutines.我们知道结果集有多大,所以我们在启动任何 goroutine 之前预先分配所有的插槽。 This eliminates any contention over the slice object itself这消除了对切片对象本身的任何争用

make(.., len(searches))
^^^^     ^^^^^^^^^^^^^

We then promote the index number and search property to a closure for each iteration, so there is no contention over the variables being used by the loop/goroutines然后我们将索引号和搜索属性提升为每次迭代的闭包,因此不会对循环/goroutine 使用的变量产生争用

    i, search := i, search

And finally, each worker operates on a singular slot in the pre-sized slice:最后,每个工作人员在预定大小的切片中的单个插槽上操作:

        results[i] = result

The workers are guaranteed to only perform read operations on the "results" slice to find out where their element is ( results[i] ).工作人员保证只对“结果”切片执行读取操作,以找出他们的元素在哪里( results[i] )。

This particular pattern is limiting, you can't use the results until all the workers are completed.这种特殊的模式是有限制的,在所有工作人员都完成之前你不能使用结果。 So ask yourself what you're going to do next when deciding whether to use this or a channels-based pipeline workflow.因此,在决定是使用此工作流程还是基于渠道的管道工作流程时,请问问自己接下来要做什么。

results := getSearchResults(searches)
statistics := analyzeResults(results)
for stats := range statistics {
    our.Write("{%s}\n", stats.String())
}

If the analysis of a given result is independent of any other, this is a good candidate for a channel-based workflow.如果对给定结果的分析独立于任何其他结果,则这是基于通道的工作流程的理想选择。

But if the analysis depends on order, or has different results depending on each other then you may not have any choice but to serialize the flow.但是如果分析依赖于顺序,或者有不同的结果,那么你可能别无选择,只能序列化流程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM