WaitGroup 实现并发等待

  • WaitGroup 类实现的功能是:等待一系列协程并发地执行完毕。如果不等待所有协程执行完毕,可能会导致一些线程安全问题。sync.WaitGroup 包含 3 个方法:
方法作用
Add(delta int)主协程调用该方法,设置 delta 为需要等待的协程数量
Done()每个子协程运行起来,当每个子协程执行结束后,调用 Done() 表示子协程运行结束, delta
Wait()当所有协程执行完毕后,代码块可使用 Wait() ,当 delta ==0时,才执行后续代码

例子:优化 hello.go 程序

//原来的代码
package main

import (
   "fmt"
   "time"
)

func hello(i int) {
   fmt.Printf("hello goroutine: %v\n", i)
}

func main() {
   for i := 0; i < 5; i++ {
      go func(j int) {
         hello(j)
      }(i)
   }
   time.Sleep(time.Second) //等待上面的协程执行完毕
}

输出:

hello goroutine: 1
hello goroutine: 2
hello goroutine: 0
hello goroutine: 3
hello goroutine: 4

在旧的代码中,第 19 行:由于不清楚上面 5 个协程什么时候执行完毕,因此只能人为粗略地估计协程 1 秒后执行完毕。因此,只能通过暴力调用 time.Sleep() 来等待 1 秒。调用 WaitGroup 后,就能自动判断所有协程执行完毕,立马开始后续代码的执行,提高程序运行效率。

package main

import (
   "fmt"
   "sync"
)

func hello(i int) {
   fmt.Printf("hello goroutine: %v\n", i)
}

func main() {
   wg := sync.WaitGroup{} //WaitGroup类实例化
   //1.调用Add(),声明协程的数量delta=5
   wg.Add(5)
   //协程执行
   for i := 0; i < 5; i++ {
      go func(j int) {
         //2.每个协程执行完后,调用Done(),delta--
         defer wg.Done()
         hello(j)
      }(i)
   }
   //3.调用Wait(),等待全部协程执行完毕(即delta==0),才执行后续代码
   wg.Wait()

   fmt.Println("所有协程执行完毕,可执行下一项操作...")
}

输出:

hello goroutine: 4
hello goroutine: 1                   
hello goroutine: 0                   
hello goroutine: 3                   
hello goroutine: 2                   
所有协程执行完毕,可执行下一项操作...

优化后的代码无需等待 1 秒,可以等所有协程执行完毕后,自动无缝切换后续代码的执行。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐