看了几个Web应用程序示例和样板,他们采取的方法往往采用这种形式(我在这里使用Gin处理程序作为示例,并假想用户和计费&#34 ; repository"从数据库或外部API获取数据的结构。我省略了错误处理以使示例更短):
func GetUserDetailsHandler(c *gin.Context) {
//this result presumably comes from the app's database
var userResult = UserRepository.FindById( c.getInt("user_id") )
//assume that this result comes from a different data source (e.g: a different database) all together, hence why we're not just doing a join query with "User"
var billingInfo = BillingRepository.FindById( c.getInt("user_id") )
c.JSON(http.StatusOK, gin.H {
user_data : userResult,
billing_data : billingInfo,
})
return
}
在上面的场景中,调用" User.FindById"可能会使用某种数据库驱动程序,但据我所知,所有可用的Golang数据库/ ORM库都在"同步"中返回数据。时尚(例如:作为返回值,而不是通过渠道)。因此,调用" User.FindById"在我继续执行" BillingInfo.FindById"之前,它会阻止它完成,因为它们可以并行工作,所以它们并不理想。
所以我认为最好的想法是利用go例程+ syncGroup来解决问题。像这样:
func GetUserDetailsHandler(c *gin.Context) {
var waitGroup sync.WaitGroup
userChannel := make(chan User);
billingChannel := make(chan Billing)
waitGroup.Add(1)
go func() {
defer waitGroup.Done()
userChannel <- UserRepository.FindById( c.getInt("user_id") )
}()
waitGroup.Add(1)
go func(){
defer waitGroup.Done()
billingChannel <- BillingRepository.FindById( c.getInt("user_id") )
}()
waitGroup.Wait()
userInfo := <- userChannel
billingInfo = <- billingChannel
c.JSON(http.StatusOK, gin.H {
user_data : userResult,
billing_data : billingInfo,
})
return
}
现在,这可能就是这个工作。但是对我来说似乎不必要的冗长,并且可能容易出错(如果我忘记了#34;在任何常规程序之前添加&#34;或者如果我忘记&#34;等待&#34;,那么这一切碎成片)。这是唯一的方法吗?或者是否有一些我错过的更简单的东西?
答案 0 :(得分:1)
也许是这样的
package main
import (
"fmt"
)
func GetUserDetailsHander(c *gin.Context) {
var userInfo USERINlFO
var billingInfo BILLL
err := parallel(
func() (e error) {
userInfo, e = UserRepository.FindById(c.getInt("user_id"))
return
},
func() (e error) {
billingInfo, e = BillingRepository.FindById(c.getInt("user_id"))
return
},
)
fmt.Println(err)
c.JSON(http.StatusOK, gin.H{
user_data: userResult,
billing_data: billingInfo,
})
return
}
func parallel(do ...func() error) error {
var err error
rcverr := make(chan error)
for _, d := range do {
go func(do func() error) {
rcverr <- do()
}(d)
}
for range do {
e := <-rcverr
if e != nil {
err = e // return here for fast path
}
}
close(rcverr)
return err
}