21 go并发编程-下
如何等待一组goroutine结束
1. 使用不带缓冲区的channel实现。
原理:
每个goroutine都往一个channel里写入一个值,然后我们去遍历这个管道的数值,由于不带缓冲区,那么必须等到写入端写入一个值后,for循环才能循环下去。这样等循环完成后,那么goroutine也都执行完成了。
实现前提:goroutine必须往channel写入一个值,否则for循环的时候会报deadlock的错误!
代码如下所示:
// main
package main
import (
"fmt"
"time"
)
func process(i int, ch chan bool) {
fmt.Println("started Goroutine ", i)
time.Sleep(2 * time.Second)
fmt.Printf("GoRoutine %d ended\n", i)
ch <- true //写入一个值,必须写入
}
func main() {
no := 3
exitChan := make(chan bool, no)
for i := 0; i < no; i++ {
go process(i, exitChan)
}
for i := 0; i < no; i++ { // 遍历这个channel
<-exitChan
}
fmt.Println("all goroutines are done!")
}
2. 使用sync.WaitGroup实现。
先说说WaitGroup的用途:它能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成。
WaitGroup总共有三个方法:Add(delta int)、Done()、Wait()。简单的说一下这三个方法的作用。
- Add:添加或者减少等待goroutine的数量
- Done:相当于Add(-1)
- Wait:执行阻塞,直到所有的WaitGroup数量变成0
package main
import (
"fmt"
"sync"
"time"
)
func process(i int, wg *sync.WaitGroup) {
fmt.Println("started Goroutine ", i)
time.Sleep(2 * time.Second)
fmt.Printf("Goroutine %d ended\n", i)
wg.Done()
}
func main() {
no := 10
var wg sync.WaitGroup
for i := 0; i < no; i++ {
wg.Add(1)
go process(i, &wg)
}
wg.Wait()
fmt.Println("all goroutines are done!")
}