- 此函数例子,完整展示了使用 协程 加 waitgroup, 锁,以及通道,和 通道close广播机制,完成并发修改数据库多行返回值的操作,是非常标准的golang并发编程范式
- 后边我会详细的跟大家介绍 协程 , waitgroup, 锁,以及通道,和 通道close广播机制的原理
业务处理函数, 获取用户列表
func ListUser(username string, offset, limit int) ([]*model.UserInfo, uint, error) {
infos := make([]*model.UserInfo, 0)
users, count, err := model.ListUser(username, offset, limit)
if err != nil {
return nil, count, err
}
ids := []uint{}
for _, user := range users {
ids = append(ids, user.ID)
}
wg := sync.WaitGroup{}
userList := model.UserList{
Lock: new(sync.Mutex),
IdMap: make(map[uint]*model.UserInfo, len(users)),
}
errChan := make(chan error, 1)
声明一个用来做关闭通知的通道
finished := make(chan bool, 1)
for _, u := range users {
每个协程加入waitgroup等待
wg.Add(1)
go func(u *model.UserModel) {
每个协程 设置done操作
defer wg.Done()
shortID, err := util.GenShortID()
if err != nil {
errChan <- err
return
}
更新数据时加锁, 保持一致性
userList.Lock.Lock()
defer userList.Lock.Unlock()
userList.IdMap[u.ID] = &model.UserInfo{
ID: u.ID,
Username: u.Username,
SayHello: fmt.Sprintf("Hello %s", shortID),
Password: u.Password,
CreatedAt: util.TimeToStr(&u.CreatedAt),
UpdatedAt: util.TimeToStr(&u.UpdatedAt),
DeletedAt: util.TimeToStr(u.DeletedAt),
}
}(u)
}
go func() {
wg.Wait()
等待所有协程完成之后,关闭通道,close有广播机制
close(finished)
}()
select {
如果监听到finished通道的关闭信号则继续执行
case <-finished:
case err := <-errChan:
return nil, count, err
}
for _, id := range ids {
infos = append(infos, userList.IdMap[id])
}
return infos, count, nil
}