如何尽早从循环内的古鲁特返回错误?

我在一个循环中有一个goroutine,我处理错误的方式是,我将其添加到一个通道,在所有goroutines完成后,我检查是否有错误,然后相应地返回。


这样做的问题是,我想在收到错误后立即返回错误,这样我就不会花时间等待所有goroutines完成,因为它效率低下。


我尝试添加语句,但它不起作用,我无法在goroutines中添加语句,因为我也想退出for循环和函数。selectselecttry


我该怎么做?


代码如下:


package main


import (

    "sync"

    "runtime"

    "fmt"

    "errors"

)


func try() (bool, error) {

    wg := new(sync.WaitGroup)


    s := []int{0,1,2,3,4,5}

    ec := make(chan error)

    

    for i, val := range s {

    /*

        select {

             case err, ok := <-ec:

        if ok {

            println("error 1", err.Error())

            return false, err

        }

            default:

            }

    */

        wg.Add(1)

        i := i

        val := val

        go func() {

            err := func(i int, val int, wg *sync.WaitGroup) error {

                defer wg.Done()

                

                if i == 3 {

                    return errors.New("one error")

                } else {

                    return nil

                }

                

            }(i, val, wg)

            if err != nil {

                ec <- err

                return

            }

        }()

    }

    wg.Wait()

    

    select {

    case err, ok := <-ec:

        if ok {

            println("error 2", err.Error())

            return false, err

        }

    default:

    }

    

    return true, nil

}


func main() {

    runtime.GOMAXPROCS(runtime.NumCPU())

    b, e := try()

    if e != nil {

        fmt.Println(e.Error(), b)

    } 

    

}


皈依舞
浏览 99回答 2
2回答

繁星淼淼

在你的陈述之前,你实际上是在等待所有的goroutines回来。wg.Wait()select这样做的问题是,我想在收到错误后立即返回错误我假设您的意思是,一旦其中任何一个返回错误,就停止运行goroutines。在这种情况下,您可以使用来管理取消,但更好的是错误组。组,它很好地结合了上下文功能和同步:context.Context包错误组为处理常见任务的子任务的 goroutine 组提供同步、错误传播和上下文取消。特别是Group.Go:返回非 nil 错误的第一个调用将取消该组;其错误将由 Wait 返回。import (&nbsp; &nbsp; "sync"&nbsp; &nbsp; "runtime"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "errors"&nbsp; &nbsp; "golang.org/x/sync/errgroup")func try() (bool, error) {&nbsp; &nbsp; errg := new(errgroup.Group)&nbsp; &nbsp; s := []int{0,1,2,3,4,5}&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; for i, val := range s {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; i := i&nbsp; &nbsp; &nbsp; &nbsp; val := val&nbsp; &nbsp; &nbsp; &nbsp; errg.Go(func() error {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return func(i int, val int) error {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if i == 3 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return errors.New("one error")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }(i, val)&nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; if err := errg.Wait(); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; // handle error&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; return true, nil}https://play.golang.org/p/lSIIFJqXf0W

紫衣仙女

我发现坟墓对此很有用。下面是一个精简的非工作示例,它显示了要点,而无需在循环中处理变量封装之类的事情。它应该给你这个想法,但我很乐意澄清任何一点。package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "gopkg.in/tomb.v2"&nbsp; &nbsp; "sync")func main() {&nbsp; &nbsp; ts := tomb.Tomb{}&nbsp; &nbsp; s := []int{0,1,2,3,4,5}&nbsp; &nbsp; for i, v := range s {&nbsp; &nbsp; &nbsp; &nbsp; ts.Go(func() error {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // do some work here or return an error, make sure to watch the dying chan, if it closes,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //then one of the other go-routines failed.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case <- ts.Dying():&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case err := <- waitingForWork():&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; }&nbsp; &nbsp; // If an error appears here, one of the go-routines must have failed&nbsp; &nbsp; err := ts.Wait()&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(err)&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go