关于协程的使用问题
来源:6-1 channel
burningx
2021-09-29 19:25:19
老师好,我在写一个功能,是获取用户的一些统计信息,分别有提问总数
、点赞总数
、回答总数
。
我的想法是开3个协程,分别请求三个方法获取对应的统计数据,下面是我的实现代码,数据是能正确获取,但是我总觉得这么写的代码怪怪的,请教老师,我这么实现合理吗?或者有其他更优的方法实现?
func (s *Service) doGetTotalByUser(c chan fields.Total, f func() fields.Total) {
defer close(c)
total := f()
c <- total
}
func (s *Service) GetStatisticByUser(c context.Context, req *qapb.StatisticByUserRequest) (*qapb.StatisticByUserResponse, error) {
userID := uint32(req.UserId)
postTotalChan := make(chan fields.Total)
replyTotalChan := make(chan fields.Total)
praiseTotalChan := make(chan fields.Total)
go s.doGetTotalByUser(postTotalChan, func() fields.Total {
postTotal, err := s.Mysql.GetPostTotalByUser(c, userID)
if err != nil {
zap.S().Error("无法获取用户问题总数: %v", err)
}
return postTotal
})
go s.doGetTotalByUser(replyTotalChan, func() fields.Total {
replyTotal, err := s.Mysql.GetReplyTotalByUser(c, userID)
if err != nil {
zap.S().Errorf("无法获取用户回复总数: %v", err)
}
return replyTotal
})
go s.doGetTotalByUser(praiseTotalChan, func() fields.Total {
praiseTotal, err := s.Mysql.GetPraiseTotalByUser(c, userID)
if err != nil {
zap.S().Errorf("无法获取用户被点赞总数: %v", err)
}
return praiseTotal
})
postTotal := <-postTotalChan
replyTotal := <-replyTotalChan
praiseTotal := <-praiseTotalChan
response := &qapb.StatisticByUserResponse{
PostTotal: postTotal.Int(),
ReplyTotal: replyTotal.Int(),
PraiseTotal: praiseTotal.Int(),
}
return response, nil
}
1回答
总体框架没什么问题。不过错误处理流程不太顺利。
我们很可能希望把错误通过response返回出去,而不是服务器端打一个日志然后静默的返回0。这里可以考虑把fields.Total和error合起来,做一个struct,通过channel把这个struct返回出去。那么构造response的时候就可以明确地说到底哪个值出错了。
还有个小改进,其实doGetTotalByUser函数不需要,各goroutine直接把数据通过channel送出去即可。doGetTotalByUser的存在就是为了close channel。但是channel其实并不总是需要close的。channel在垃圾回收的时候资源就会被释放,close只是一个特殊的信号,通知接收方我不再发送数据。在我们这里很明确一共就一个数据,所以不需要close。
相似问题