并行获取多个字段的模式

我需要从外部服务为我的系统并行获取多个字段(在本例中,通过 Name()、Age() 和 CanDrive() 方法模拟)。

fetchUser() 方法可以实现我想要的功能,但它似乎太冗长了,特别是如果您认为我可以有 10 个以上的字段。我有更好的方法可以实现这一点吗?

游乐场:https://play.golang.org/p/90sNq1GmrD8

代码(与游乐场中相同):

package main


import (

    "fmt"

    "sync"

)


type User struct {

    Name string

    Age int

    CanDrive *bool

}


func Name() (string, error) {

    return "foobar", nil

}


func Age() (int, error) {

    return 25, nil

}


func CanDrive() (bool, error) {

    return true, nil

}


func fetchUser() (*User, error) {

    var wg sync.WaitGroup

    errs := make(chan error)


    user := &User{}


    wg.Add(1)

    go func() {

        var err error

        defer wg.Done()

        user.Name, err = Name()

        errs <- err

    }()


    wg.Add(1)


    go func() {

        var err error

        defer wg.Done()

        user.Age, err = Age()

        errs <- err

    }()


    wg.Add(1)

    go func() {

        defer wg.Done()

        canDrive, err := CanDrive()

        if err == nil {

            user.CanDrive = &canDrive

        }

        errs <- err

    }()


    // wait until all go-routines are completed successfully

    // if that's the case, close the errs channel

    go func() {

        wg.Wait()

        close(errs)

    }()


    // keep waiting for errors (or for the error channel to be closed

    // if all calls succeed)

    for err := range errs {

        if err != nil {

            return nil, err

        }

    }


    return user, nil

}


func main() {

    user, _ := fetchUser()

    fmt.Println(user)

}


jeck猫
浏览 89回答 1
1回答

牛魔王的故事

在不了解您的场景的更多细节的情况下,我唯一的建议是将 Go 例程错误处理分离到另一个包中。幸运的是,已经存在一个可以执行相同操作的包,名为errgroup. 以下是使用该包的原始代码的实现errgroup:package mainimport (    "context"    "fmt"    "golang.org/x/sync/errgroup")type User struct {    Name     string    Age      int    CanDrive *bool}func Name() (string, error) {    return "foobar", nil}func Age() (int, error) {    return 25, nil}func CanDrive() (bool, error) {    return true, nil}func fetchUser(ctx context.Context) (*User, error) {    group, ctx := errgroup.WithContext(ctx)    user := &User{}    group.Go(func() (err error) {        user.Name, err = Name()        return    })    group.Go(func() (err error) {        user.Age, err = Age()        return    })    group.Go(func() error {        canDrive, err := CanDrive()        if err == nil {            user.CanDrive = &canDrive        }        return err    })    if err := group.Wait(); err != nil {        return nil, err    }    return user, nil}func main() {    user, err := fetchUser(context.Background())    fmt.Println(user, err)}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go