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

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

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

Go
皈依舞 2022-09-05 15:26:33
我在一个循环中有一个goroutine,我处理错误的方式是,我将其添加到一个通道,在所有goroutines完成后,我检查是否有错误,然后相应地返回。这样做的问题是,我想在收到错误后立即返回错误,这样我就不会花时间等待所有goroutines完成,因为它效率低下。我尝试添加语句,但它不起作用,我无法在goroutines中添加语句,因为我也想退出for循环和函数。selectselecttry我该怎么做?代码如下:package mainimport (    "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)    }     }
查看完整描述

2 回答

?
繁星淼淼

TA贡献1775条经验 获得超11个赞

在你的陈述之前,你实际上是在等待所有的goroutines回来。wg.Wait()select

这样做的问题是,我想在收到错误后立即返回错误

我假设您的意思是,一旦其中任何一个返回错误,就停止运行goroutines。

在这种情况下,您可以使用来管理取消,但更好的是错误组。组,它很好地结合了上下文功能和同步:context.Context

包错误组为处理常见任务的子任务的 goroutine 组提供同步、错误传播和上下文取消。

特别是Group.Go

返回非 nil 错误的第一个调用将取消该组;其错误将由 Wait 返回。

import (

    "sync"

    "runtime"

    "fmt"

    "errors"

    "golang.org/x/sync/errgroup"

)


func try() (bool, error) {

    errg := new(errgroup.Group)


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

    

    for i, val := range s {       

        i := i

        val := val


        errg.Go(func() error {

            return func(i int, val int) error {

                if i == 3 {

                    return errors.New("one error")

                } else {

                    return nil

                }

            }(i, val)

        })

    }

    

    if err := errg.Wait(); err != nil {

        // handle error

    }

    

    return true, nil

}

https://play.golang.org/p/lSIIFJqXf0W


查看完整回答
反对 回复 2022-09-05
?
紫衣仙女

TA贡献1839条经验 获得超15个赞

我发现坟墓对此很有用。下面是一个精简的非工作示例,它显示了要点,而无需在循环中处理变量封装之类的事情。它应该给你这个想法,但我很乐意澄清任何一点。


package main


import (

    "fmt"

    "gopkg.in/tomb.v2"

    "sync"

)


func main() {

    ts := tomb.Tomb{}

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


    for i, v := range s {

        ts.Go(func() error {

            // do some work here or return an error, make sure to watch the dying chan, if it closes, 

            //then one of the other go-routines failed.

            select {

            case <- ts.Dying():

                return nil

            case err := <- waitingForWork():

                if err != nil {

                    return err

                }

                return nil

            }

        })

    }


    // If an error appears here, one of the go-routines must have failed

    err := ts.Wait()

    if err != nil {

        fmt.Println(err)

    }

}


查看完整回答
反对 回复 2022-09-05
  • 2 回答
  • 0 关注
  • 98 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号