go中的WaitGroups

简介: go中的WaitGroups

什么是WaitGroups?


WaitGroups是同步你的goroutines的一种有效方式。想象一下,你和你的家人一起驾车旅行。你的父亲在一个条形商场或快餐店停下来,买些食物和上厕所。你最好想等大家回来后再开车去地平线。WaitGroups帮助你做到这一点。


WaitGroups是通过调用标准库中的sync包来定义的。


var wg sync.WaitGroup


那么,什么是WaitGroup呢?WaitGroup是一个结构,它包含了程序需要等待多少个goroutine的某些信息。它是一个包含你需要等待的goroutines数量的组。


WaitGroups有三个最重要的方法: Add, DoneWait


  • Add: 添加到你需要等待的goroutines的总量上。
  • Done: 从你需要等待的goroutines总数中减去一个。
  • Wait: 阻止代码继续进行,直到没有更多的goroutines需要等待。


如何使用WaitGroups


让我们来看看一段代码:


package main
import (
    "fmt"
    "sync"
    "time"
)
func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer wg.Done()
        fmt.Println(time.Now(), "start")
        time.Sleep(time.Second)
        fmt.Println(time.Now(), "done")
    }()
    wg.Wait()
    fmt.Println(time.Now(), "exiting...")
}
2022-08-21 17:01:54.184744229 +0900 KST m=+0.000021800 start
2022-08-21 17:01:55.184932851 +0900 KST m=+1.000210473 done
2022-08-21 17:01:55.18507731 +0900 KST m=+1.000354912 exiting...
  • 我们首先初始化一个WaitGroup wg的实例。
  • 然后我们在wg中添加1,因为我们要等待一个goroutine完成。
  • 然后我们运行这个goroutine。在goroutine内部,我们对wg.Done()进行延迟调用,以确保我们递减要等待的goroutine的数量。如果我们不这样做,那么代码将永远等待goroutine完成,并将导致死锁。
  • goroutine调用之后,我们要确保阻断代码,直到WaitGroup为空。我们通过调用wg.Wait()来做到这一点。


为什么使用WaitGroups而不是channel?


现在我们知道了如何使用WaitGroups,一个自然而然的想法将我们引向这个问题:为什么使用WaitGroups而不是通道?


根据我的经验,有几个原因。


  • WaitGroups往往更直观。当你阅读一段代码时,当你看到一个WaitGroup时,你会立即知道代码在做什么。方法的名称很明确,而且直奔主题。然而,对于通道来说,有时就不是那么清楚了。使用通道是很聪明的,但当你阅读一段复杂的代码时,理解起来会很麻烦。
  • 有的时候,你不需要使用通道。例如,让我们看一下这段代码:
var wg sync.WaitGroup
  for i := 0; i < 5; i++ {
      wg.Add(1)
      go func() {
          defer wg.Done()
          fmt.Println(time.Now(), "start")
          time.Sleep(time.Second)
          fmt.Println(time.Now(), "done")
      }()
  }
  wg.Wait()
  fmt.Println(time.Now(), "exiting...")


你可以看到,这个goroutine并没有与其他goroutine进行数据交流。如果你的goroutine是一次性的工作,你不需要知道结果,使用WaitGroup是可取的。现在看一下这段代码:


ch := make(chan int)
  for i := 0; i < 5; i++ {
      go func() {
          randomInt := rand.Intn(10)
          ch <- randomInt
      }()
  }
  for i := 0; i < 5; i++ {
      fmt.Println(<-ch)
  }


这里,goroutine正在向 channel 发送数据。在这些情况下,我们不需要使用WaitGroup,因为这将是多余的。如果接收已经做了足够的阻塞,为什么还要等待goroutine完成?


WaitGroups是专门用来处理等待goroutines的。我觉得通道的主要目的是为了交流数据。你不能用WaitGroup来发送和接收数据,但你可以用一个channel来同步你的goroutines


最后,没有正确的答案。我知道这可能很烦人,但这取决于你和你工作的团队。无论什么方法都是最好的,没有答案是错误的。我个人倾向于使用WaitGroups进行同步,但你的情况可能有所不同。选择对你来说最直观的东西。


需要注意的一件事


有时,你可能需要将WaitGroup实例传递给goroutine。可能有几个WaitGroup来处理不同的goroutine,也可能是一种设计选择。不管是什么原因,请确保传递指向WaitGroup的指针,像这样:


var wg sync.WaitGroup
for i := 0; i < 5; i++ {
    wg.Add(1)
    go func(wg *sync.WaitGroup) {
        defer wg.Done()
        fmt.Println(time.Now(), "start")
        time.Sleep(time.Second)
        fmt.Println(time.Now(), "done")
    }(&wg)
}
wg.Wait()
fmt.Println(time.Now(), "exiting...")


原因是Go是一种值传递的语言。这意味着每当你向一个函数传递一个参数时,Go会复制一个参数并传递给它而不是原始对象。在这种情况下发生的是,整个WaitGroup对象将被复制,这意味着goroutine将处理一个完全不同的WaitGroup。wg.Done()不会从原始的wg中减去,而是减去它的一个副本,这个副本只存在于goroutine中。


总结


通过使用WaitGroups,我们可以轻松同步goroutines,从而确保我们的代码在正确的时间执行。尽管通道也可以用于同步,但WaitGroups通常更直观且更易于阅读。在使用WaitGroup时,请确保正确传递指向WaitGroup的指针,以防止出现副本问题。无论您选择哪种方法,都应该选择最直观和最适合您和您的团队的方法。

相关文章
|
存储 敏捷开发 缓存
中台架构介绍和应用价值
中台架构介绍和应用价值
1714 0
|
4月前
|
机器学习/深度学习 人工智能 运维
机器学习不是“银弹”,但能救你于告警地狱:AIOps 减噪的 3 个实战方法(Motadata 实战版)
机器学习不是“银弹”,但能救你于告警地狱:AIOps 减噪的 3 个实战方法(Motadata 实战版)
467 10
|
8月前
|
人工智能 监控 数据可视化
让历史经验自动预警:2025年场景化进度监控工具实践指南
本报告系统梳理进度监控工具四代演进路径,深入解析AI、区块链、联邦学习等技术在智能进度监控系统中的应用,涵盖核心功能模块、可视化分析、主流工具选型及实施方法论,展望下一代技术趋势,助力项目管理智能化转型。
350 0
|
10月前
|
存储 人工智能 自然语言处理
几分钟创建一个带有业务数据的AI智能客服
本文介绍如何利用阿里云百炼和AppFlow快速创建企业微信客服或网页客服。首先,通过上传企业知识文件和创建大模型问答应用,获取AI推理API服务;接着,在AppFlow控制台新建AI助手并导入配置好的模型,设置对话背景、欢迎语及预设问题等;最后,选择Web集成或企业微信集成方式部署客服系统。整个过程简单易操作,无需技术背景,适合非技术人员使用。文章还提到支持自定义域名绑定以及更多渠道发布选项,助力企业高效搭建专属智能客服。
1127 12
几分钟创建一个带有业务数据的AI智能客服
|
人工智能 Java API
Spring AI与DeepSeek实战一:快速打造智能对话应用
在 AI 技术蓬勃发展的今天,国产大模型DeepSeek凭借其低成本高性能的特点,成为企业智能化转型的热门选择。而Spring AI作为 Java 生态的 AI 集成框架,通过统一API、简化配置等特性,让开发者无需深入底层即可快速调用各类 AI 服务。本文将手把手教你通过spring-ai集成DeepSeek接口实现普通对话与流式对话功能,助力你的Java应用轻松接入 AI 能力!虽然通过Spring AI能够快速完成DeepSeek大模型与。
1885 11
|
负载均衡 算法 网络安全
阿里云WoSign SSL证书申请指南_沃通SSL技术文档
阿里云平台WoSign品牌SSL证书是由阿里云合作伙伴沃通CA提供,上线阿里云平台以来,成为阿里云平台热销的国产品牌证书产品,用户在阿里云平台https://www.aliyun.com/product/cas 可直接下单购买WoSign SSL证书,快捷部署到阿里云产品中。
2949 8
阿里云WoSign SSL证书申请指南_沃通SSL技术文档
|
Java Go 调度
Go语言并发(一)——goroutine与Waitgroup
Go语言并发(一)——goroutine与Waitgroup
187 0
|
人工智能 数据库连接 Go
golang defer 详解
golang defer 详解
340 0
|
存储 Prometheus 监控
Prometheus 的扩展与集成
【8月更文第29天】Prometheus 是一款非常强大的监控系统,它不仅能够采集和存储时间序列数据,还提供了丰富的生态系统来扩展其功能。本文将介绍如何通过自定义 Exporters 和集成中间件(如 Thanos)来扩展 Prometheus 的能力。
548 1
|
SQL 缓存 运维
使用篇丨链路追踪(Tracing)很简单:链路拓扑
使用篇丨链路追踪(Tracing)很简单:链路拓扑
32095 101

热门文章

最新文章

下一篇
开通oss服务