首页 > 编程笔记 > Go语言笔记 阅读:11

Go语言sync.WaitGroup实现同步等待(附带实例)

在 Go 语言中,主函数 main() 执行并发之后就会往下执行,当主函数 main() 的代码执行完成后就会终止整个程序运行,它不会等待并发程序的执行结果,主程序终止后就无法查看和得到并发程序的数据和执行结果。

若要使主程序能够等待并发程序完成执行,可以使用内置包 sync 的 WaitGroup 实现。

WaitGroup 称为同步等待组,它是通过计数器方式实现等待的,计数器的数值代表程序中有多少个并发程序,使用示例如下:
package main

import (
   "fmt"
   "sync"
)

// 创建同步等待组对象
var wg sync.WaitGroup

// 定义函数,用于执行并发操作
func fun1() {
   for i := 1; i <= 3; i++ {
        fmt.Println("fun1。。i,", i)
   }
   // 代表完成并发,同步等待组的等待对象减1
   wg.Done()
}

// 定义函数,用于执行并发操作
func fun2() {
   for j := 1; j <= 3; j++ {
        fmt.Println("fun2。。j,", j)
   }
   // 代表完成并发,同步等待组的等待对象减1
   wg.Done()
}

func main() {
   // 设置同步等待组最大的等待数量
   wg.Add(2)
   // 执行并发
   go fun1()
   go fun2()
   fmt.Println("main进入阻塞状态。。等待并发程序结束。。")
   // 主程序进入阻塞状态,等待并发程序执行完成
   wg.Wait()
   fmt.Println("main解除阻塞。。")
}
运行上述代码,运行结果为:

main进入阻塞状态。。等待并发程序结束。。
fun1。。i,1
fun2。。j,1
fun2。。j,2
fun2。。j,3
fun1。。i,2
fun1。。i,3
main解除阻塞。。

上述示例的代码说明如下:

1)创建同步等待组对象 wg,因为对象 wg 分别在主函数 main()、函数 fun1() 和函数 fun2() 中使用,所以将其定义为全局变量。如果在主函数 main() 中定义,执行并发的时候,需要以参数形式传递给函数 fun1() 和函数 fun2()。

2)函数 fun1() 和函数 fun2() 执行完成后都必须使用 wg 调用 Done() 方法,让主程序知道并发程序已完成执行,解除主程序的阻塞等待。

3)主函数 main() 在执行并发之前,必须使用 wg 调用 Add() 方法设置等待数量,比如 wg.Add(2) 是等待两个并发程序执行完成。

4)并发程序启动后,主函数 main() 必须使用 wg 调用 Wait() 方法设置等待状态,当所有并发程序执行完成并调用了 wg 的 Done() 方法,主函数 main() 才会解除等待状态。

综上所述,使用内置包 sync 的 WaitGroup 实现同步等待的过程如下:
1)使用 WaitGroup 创建同步等待组对象 wg。

2)wg 调用 Add() 设置并发程序的等待数量,Add() 用来设置 wg 计数器的值。

3)wg 的等待数量必须与并发程序的数量一致。如果 wg 等待数量大于并发程序的数量,则提示 fatal error: all goroutines are asleep – deadlock 异常;如果 wg 等待数量小于并发程序的数量,主程序只会随机等待其中一个并发程序。

4)并发程序启动之后,主程序必须调用 wg 的 Wait() 进入阻塞等待状态,直到 wg 的计数器为 0 才解除阻塞等待状态。

5)并发程序执行完成后必须由 wg 调用 Done(),该方法是将 wg 的计数器执行减 1 计算。当 wg 的计数器为 0 就会解除 Wait() 的阻塞等待状态,使主程序继续往下执行剩余的代码。

相关文章