我刚开始使用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方法必须在最后完成。
我必须如何实现goroutines与通道,以执行好这些调用?
先谢谢你
在不了解你的应用的情况下,不可能说并行是否会有效。如果你认为会有效,你可以做这样的事情。
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()
这使用了 群体,它是一个方便的工具,用于等待返回错误的函数组。
如果这些资源获取器实现了一个通用的接口,并且能够支持 context.Context
.