【问题标题】:How to implement goroutine to perform well requests如何实现 goroutine 来执行良好的请求
【发布时间】:2020-09-04 11:55:43
【问题描述】:

我是从golang开始的,出于性能原因,我需要修改一些方法:

我有下一个方法:

func (fs *ServiceImpl) GetContext(Item *models.Item, CallerID *int64, txn newrelic.Transaction) (models.Context, error) {
    var context models.Context

    //Resource1
    item := Item
    resource1, err := getResource1(fs, Item, txn)

    if err != nil {
        logger.Error("error", err)
    }

    context.Item = item
    context.Resource1 = resource1

    //Resource2
    resource2, err := getResource2(fs, Item, CallerID, txn)

    if err != nil {
        logger.Error("error", err)
    }

    context.Resource2 = resource2

    //Resource3
    resource3, err := getResource3(fs, Item, txn)

    if err != nil {
        logger.Error("error", err)
    }

    context.Resource3 = resource3

    return context, err
}

那么我有:

func getResource1(fs *ServiceImpl, Item *models.Item, txn Transaction) (*models.Resource1, error) {
    r1 := models.Resource1{}

    c1, err := fs.C1Provider.GetC1(Item.C1ID, txn)

    if err == nil {
        c1.C1s = &c1.PathFromRoot
    } else {
        logger.Errorf("error", err)
    }

    u1, err := fs.U1Provider.GetU1(Item.U1ID, txn)

    if err == nil {
        r1.StoreType = &u1.U1Type
        r1.ReputationLevel = &u1.Reputation.LevelID
    } else {
        logger.Errorf("error", err)
    }

    return &r1, err
}
func getResource2(fs *ServiceImpl, Item *models.Item, CallerID *int64, txn Transaction) ([]models.Resource2, error) {
    var r2 []models.Resource2

    ri2, err := getAux1R1(fs, Item, CallerID, txn)
    r2 = append(experiments, *ri2)

    return r2, err
}

func getAux1R2(fs *ServiceImpl, Item *models.Item, CallerID *int64, txn Transaction) (*models.Resource2, error) {
    if CallerID == nil {
        return &models.Resource2{Name: "XXX", Variant: "DEFAULT"}, nil
    }

    seed := strconv.FormatInt(*CallerID, 10)
    param := models.Resource2RequestParam{
        Resource2Name: "XXX",
        Seed:           seed
    }

    r2, err := getAux2R2(fs, param, txn)

    return r2, err
}

func getAux2R2(fs *ServiceImpl, param models.Resource2RequestParam, txn Transaction) (*models.Resource2, error) {
    exp, err := fs.Resource2Service.GetResource2Configuration(param.Resource2Name, param.Seed)

    r2 := &models.Resource2{
        Name:    exp.Resource2Name(),
        Variant: exp.VariantID(),
    }

    return r2, err
}

最后:

func getResource3(fs *ServiceImpl, Item *models.Item, txn Transaction) (*models.Resource3, error) {
    var r3 *models.Resource3

    if !utils.Contains(text.ENABLE_XXX, Item.SiID) {
        return r3, nil
    }

    pay, err := getAux1R3(fs, Item, txn)

    if err == nil {
        switch Item.SiID {
        case text.P_X:
            r3 = pay.SetForX()
        case text.P_Y:
            r3 = pay.SetForY()
        case text.P_Z:
            r3 = pay.SetForZ()
        }
    }

    return r3, err
}

func getAux1R3(fs *ServiceImpl, Item *models.Item, txn Transaction) (*models.Resource3, error) {
    result, err := fs.P1Provider.GetP1Options(Item.ID, txn)

    if err != nil {
        logger.Errorf("error", err)

        return nil, err
    }

    return result, nil
}

这些方法是api调用,需要相当长的时间:

c1, err := fs.C1Provider.GetC1(Item.C1ID, txn)
exp, err := fs.Resource2Service.GetResource2Configuration(param.Resource2Name, param.Seed)
result, err := fs.P1Provider.GetP1Options(Item.ID, txn)

我不关心调用的顺序,但GetContext方法必须在最后完成。

我必须如何实现带有通道的 goroutine 才能很好地执行此调用?

提前致谢!

【问题讨论】:

  • 您已经共享数据和一个txn 变量传递给所有这些函数。 txn 是否能够处理并发呼叫?共享数据对于并发访问是安全的,即它是只读的,还是每个函数修改它的独占部分?如果没有,您可能无法在此处使用 goroutine。

标签: go goroutine channels


【解决方案1】:

如果不了解您的应用程序的更多信息,就不可能说并行性是否有效。如果你认为会是这样,你可以这样做:

var g errgroup.Group

g.Go(func() error {
    r, err := getResourceA(...)
    if err == nil {
        context.ResourceA = r
    }
    return err
})

... get more resources ...

g.Go(func() error {
    r, err := getResourceZ(...)
    if err == nil {
       context.ResourceZ = r
    }
    return err
})

return context, g.Wait()

这使用errgroup,这是一个方便的实用程序,用于等待返回错误的函数组。

如果这些资源获取器实现了一个通用接口并支持context.Context,代码会更简洁。

【讨论】:

    猜你喜欢
    • 2018-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-25
    • 1970-01-01
    • 1970-01-01
    • 2020-05-21
    • 2018-09-03
    相关资源
    最近更新 更多