利用WaitGroup和Channel实现Go语言中的并发处理

简介

并发是现代软件开发中的一个关键方面,它使程序能够同时执行多个任务,并有效利用系统资源。在 Go 语言中,WaitGroup 和通道是强大的构造,可用于并发编程。本文探讨了在一个真实场景中简单使用 WaitGroup 和通道的方式,演示了它们如何有效地并行化操作。

WaitGroup

sync.WaitGroup 是 Go 中用于等待一组 Goroutine 完成的同步原语。它允许您协调多个 Goroutine,并确保它们都完成后再继续执行。它的工作原理如下:
1.初始化:使用 var wg sync.WaitGroup 创建一个新的 WaitGroup。

2.添加 Goroutine:在启动 Goroutine 之前,调用 wg.Add(1) 来增加 WaitGroup 的计数器。

3.Goroutine 执行:在每个 Goroutine 内部执行所需的任务,在完成后调用 wg.Done() 来减少计数器。

4.等待完成: 在启动所有 Goroutine 后,调用 wg.Wait() 来阻塞,直到计数器变为零,表示所有 Goroutine 都已完成。

Channel

通道是 Go 中用于在 Goroutine 之间进行通信的基本特性。它们实现了安全的数据交换和同步。以下是简要概述:
1.创建: 使用 make 函数声明一个通道,指定它将携带的数据类型。例如,resultChan := make(chan *DataType)。

2.发送数据: 使用 <- 运算符将数据发送到通道中,例如,resultChan <- data。

3.接收数据: 使用 <- 运算符从通道中接收数据,例如,data := <-resultChan。

4.关闭通道: 在不再需要通道时,关闭通道是很重要的,以表示不会再发送更多的数据。这可以通过 close 函数来完成,例如,close(resultChan)。
5.作用:处理协程执行时间差异的策略

示例:利用 WaitGroup 和通道:

// An highlighted block
func (that *FriendBlocksWithRidsLogic) FriendBlocksWithRids(in *friends.FriendBlocksWithRidsReq) (*friends.FriendBlocksWithRidsResp, error) {
	bService := blacklistservice.New(that.ctx, that.svcCtx)

	// 开启多协程异步调用,定义wg
	var wg sync.WaitGroup
	// 定义最大协程5个
	numRequests := 5
	// 定义chan来接受通道内数据
	resultChan := make(chan *EveryRoleBlocksInfo, numRequests)
	for _, rid := range in.GetRids() {
		wg.Add(1)
		ridV2 := rid
		go func(roleID uint64) {
			defer wg.Done()
			backList, err := bService.GetList(ridV2, in.GetPage(), in.GetPageSize())
			resultChan <- &EveryRoleBlocksInfo{RoleBlocksInfoRsp: backList, Err: err, Rid: ridV2}
		}(ridV2)
	}
	// 等待完成并关闭通道
	go func() {
		wg.Wait()
		close(resultChan)
	}()
	ridMap := make(map[uint64]*blacklistservice.BlackList)
	for result := range resultChan {
		if result.Err != nil {
			logger.Debugf(that.ctx, "rpc GetList fail rid: %+v , err : %v ", result.Rid, result.Err)
			return nil, friendErr.ErrGRPCFriendsError_FRIENDS_BLOCK_LIST_ERROR
		} else {
			ridMap[result.Rid] = result.RoleBlocksInfoRsp
		}
	}
	var data []*friends.FriendBlocksWithRidsResp_FriendBlocksWithRidsData
	return &friends.FriendBlocksWithRidsResp{
		Data: data,
	}, nil
}

在提供的代码片段中,我们看到了使用 WaitGroup 和通道来并发处理列表的用法。以下是详细说明:

1.WaitGroup: WaitGroup wg 被初始化用于协调多个 Goroutine。对于输入中的每个好友 ID(rid),都启动了一个 Goroutine 来异步获取列表。在启动每个 Goroutine 前调用 wg.Add(1),并在完成后延迟调用 wg.Done() 来指示完成。

2.通道: 创建一个通道 resultChan 用于接收每个 Goroutine 执行结果。在每个 Goroutine 内部,列表信息以及任何错误都被发送到通道中。在所有 Goroutine 完成执行后,关闭通道以表示完成。

3.处理结果: 使用一个 map ridMap 来按好友 ID(rid)聚合列表信息。当从通道接收到结果时,根据需要进行处理。如果在获取列表时发生错误,则采取适当的操作。

4.最终输出: 一旦所有 Goroutine 都完成并且结果被处理,聚合的列表信息将被转换为所需的响应格式并返回。

结论:

总之,WaitGroup 和通道是 Go 中用于管理并发和 Goroutine 之间通信的强大构造。通过利用这些原语,开发人员可以编写高效、可扩展和易维护的并发程序。提供的示例演示了它们在有效并行化任务中的应用,展示了它们在现代软件开发中的重要性。

Alt

  • 27
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值