Go - 使用 sync.WaitGroup 来实现并发操作

简介: Go - 使用 sync.WaitGroup 来实现并发操作

文章目录:

  • 前言
  • sync.WaitGroup 正确使用
  • sync.WaitGroup 闭坑指南
  • 01
  • 02
  • 03
  • 小结
  • 推荐阅读


前言

如果你有一个任务可以分解成多个子任务进行处理,同时每个子任务没有先后执行顺序的限制,等到全部子任务执行完毕后,再进行下一步处理。这时每个子任务的执行可以并发处理,这种情景下适合使用 sync.WaitGroup

虽然 sync.WaitGroup 使用起来比较简单,但是一不留神很有可能踩到坑里。

sync.WaitGroup 正确使用

比如,有一个任务需要执行 3 个子任务,那么可以这样写:

func main() {
 var wg sync.WaitGroup
 wg.Add(3)
 go handlerTask1(&wg)
 go handlerTask2(&wg)
 go handlerTask3(&wg)
 wg.Wait()
 fmt.Println("全部任务执行完毕.")
}
func handlerTask1(wg *sync.WaitGroup) {
 defer wg.Done()
 fmt.Println("执行任务 1")
}
func handlerTask2(wg *sync.WaitGroup) {
 defer wg.Done()
 fmt.Println("执行任务 2")
}
func handlerTask3(wg *sync.WaitGroup) {
 defer wg.Done()
 fmt.Println("执行任务 3")
}

执行输出:

执行任务 3
执行任务 1
执行任务 2
全部任务执行完毕.

sync.WaitGroup 闭坑指南

01

// 正确
go handlerTask1(&wg)
// 错误
go handlerTask1(wg)

执行子任务时,使用的 sync.WaitGroup 一定要是 wg 的引用类型!

02

注意不要将 wg.Add() 放在 go handlerTask1(&wg) 中!

例如:

// 错误
var wg sync.WaitGroup
go handlerTask1(&wg)
wg.Wait()
...
func handlerTask1(wg *sync.WaitGroup) {
 wg.Add(1)
 defer wg.Done()
 fmt.Println("执行任务 1")
}

注意 wg.Add() 一定要在 wg.Wait() 执行前执行!

03

注意 wg.Add()wg.Done() 的计数器保持一致!其实 wg.Done() 就是执行的 wg.Add(-1)

小结

sync.WaitGroup 使用起来比较简单,一定要注意不要踩到坑里。

其实 sync.WaitGroup 使用场景比较局限,仅适用于等待全部子任务执行完毕后,再进行下一步处理,如果需求是当第一个子任务执行失败时,通知其他子任务停止运行,这时 sync.WaitGroup 是无法满足的,需要使用到通知机制(channel)。

以上,希望对你能够有所帮助。

推荐阅读

目录
相关文章
|
1月前
|
Go
Go 语言为什么不支持并发读写 map?
Go 语言为什么不支持并发读写 map?
|
1月前
|
并行计算 数据挖掘 大数据
[go 面试] 并行与并发的区别及应用场景解析
[go 面试] 并行与并发的区别及应用场景解析
|
3月前
|
Go
go的并发初体验、加锁、异步
go的并发初体验、加锁、异步
|
1月前
|
数据采集 Go 定位技术
使用go并发网络爬虫
使用go并发网络爬虫
|
1月前
|
编译器 数据库连接 Go
Go Sync 包:并发的 6 个关键概念
Go Sync 包:并发的 6 个关键概念
|
1月前
|
Go API
Go 利用上下文进行并发计算
Go 利用上下文进行并发计算
|
11天前
|
监控 Devops 测试技术
|
1月前
|
安全 Go 调度
[go 面试] 深入理解并发控制:掌握锁的精髓
[go 面试] 深入理解并发控制:掌握锁的精髓
|
1月前
|
算法 Go 数据库
[go 面试] 并发与数据一致性:事务的保障
[go 面试] 并发与数据一致性:事务的保障
|
1月前
|
缓存 算法 Go
使用go的并发性来解决Hilbert酒店问题
使用go的并发性来解决Hilbert酒店问题
31 2