G

Golang 协程更好的进行错误处理

Yuming 代码 2022-06-02

利用 channel 来传输多个 goroutine 中的 errors

Go 的经典哲学:不要通过共享内存来通信,而是通过通信来实现内存共享

func main() {
    cherrors := make(chan error)
    wgDone := make(chan bool)

    var wg sync.WaitGroup
    wg.Add(2)
    go func() {
        //... 业务逻辑
        wg.Done()
    }()
    go func() {
        //... 业务逻辑
        err := returnErr()
        if err != nil {
            cherrors <- err
        }
        wg.Done()
    }()
    go func() {
        wg.Wait()
        close(wgDone)
    }()

    select {
    case <-wgDone:
        break
    case err := <-cherrors:
        close(cherrors)
        fmt.Println(err)
    }

    time.Sleep(time.Second)
}

func returnErr() error {
    return errors.New("出错啦。。我是错误信息")
}

使用 sync/errgroup

使用官方提供的golang.org/x/sync/errgroup标准库

type Group
    func WithContext(ctx context.Context) (*Group, context.Context)
    func (g *Group) Go(f func() error)
    func (g *Group) Wait() error
  • Go:启动一个协程,在新的 goroutine 中调用给定的函数。
  • Wait:等待协程结束,直到 Go 方法中的所有函数调用都返回,然后返回其中第一个非零错误(如果有错误的话)。
func main() {
    group := new(errgroup.Group)

    nums := []int{-1, 0, 1}
    for _, num := range nums {
        num := num
        group.Go(func() error {
            res, err := output(num)
            fmt.Println(res)
            return err
        })
    }

    if err := group.Wait(); err != nil {
        fmt.Println("Get errors: ", err)
    } else {
        fmt.Println("Get all num successfully!")
    }
}

func output(num int) (int, error) {
    if num < 0 {
        return 0, errors.New("math: square root error!")
    }
    return num, nil
}

每启动一个新的 goroutine 都直接使用 Group.Go 方法,在等待和错误处理上使用 Group.Wait 方法。

这种方法进行错误处理的好处是不需要关注非业务逻辑的控制代码,比较简洁明了。

PREV
Golang 下载私有库
NEXT
Golang 简易WS服务 - 服务端

评论(0)

发布评论