如果只有一个工作协程,需要主协程等待工作协程完成任务,可以使用通道来实现同步。
示例如下:
package main
import (
"fmt"
"time"
)
func worker(done chan bool) {
fmt.Print("working...")
// 忙一会..
time.Sleep(time.Second)
fmt.Println("done")
// 通知主协程任务完成
done <- true
}
func main() {
// 创建非缓冲通道(ps:缓冲通道也可以完成这项任务)
done := make(chan bool)
go worker(done)
// 阻塞等待worker协程任务完成
<-done
}
不了解通道可以看这篇文章 Go语言的缓冲通道和非缓冲通道。
如果需要等待有多个协程,一般有两种方式:使用缓冲通道、WaitGroup
。
1.使用缓冲通道阻塞等待所有协程的完成信息
示例如下:
package main
import (
"fmt"
"time"
)
func main() {
// 创建布尔通道
done := make(chan bool)
for i := 0; i < 5; i++ {
go func(done chan bool) {
fmt.Println(i, "start working...")
time.Sleep(2 * time.Second)
fmt.Println(i, "finish working...")
// 通知主协程任务完成
done <- true
}(done)
}
// 循环接收所有协程完成信息
for i := 0; i < 5; i++ {
<-done
}
}
- 使用 WaitGroup
使用WaitGroup
需要导入sync
包
示例如下:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
// 声明 WaitGroup
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
// 递增 WaitGroup 的计数器。
wg.Add(1)
// 1.22版本前的GoLang需要添加下面语句避免所有闭包共享单一不变的变量,详见 https://go.dev/doc/faq#closures_and_goroutines
// i := i
// 以匿名函数形式运行协程
go func(id int) {
fmt.Println(id, "start working..")
// 忙一会...
time.Sleep(2 * time.Second)
fmt.Println(id, "finish working..")
// 在函数将要结束时,递减 WaitGroup 的计数器。
// defer 会保证当函数返回时,执行紧跟 defer 的函数语句。
defer wg.Done()
}(i)
}
// 阻塞等待 WaitGroup 的计数器恢复为0,即所有协程工作完成。
wg.Wait()
}