要介紹 WaitGroup 前,我們還是用之前的程式碼來小小修改一下,下面是昨天 day14 的程式碼
// version 3 資料蒐集完就 print
func doWorker3(id int, c chan int, done chan bool) {
for n := range c {
fmt.Printf("Worker %d received %c \n", id, n)
done <- true
}
}
type worker3 struct {
in chan int
done chan bool
}
func createWorker3(id int) worker3 {
w := worker3{
in: make(chan int),
done: make(chan bool),
}
go doWorker3(id, w.in, w.done)
return w
}
func chanDemo3() {
var workers [10]worker3
for i := 0; i < 10; i++ {
workers[i] = createWorker3(i)
}
for i, worker := range workers {
worker.in <- 'a' + i // send
}
for i := 0; i < 10; i++ {
<-workers[i].done // receive
}
for i, worker := range workers {
worker.in <- 'A' + i
}
for i := 0; i < 10; i++ {
<-workers[i].done // receive
}
}
接下來的程式碼中要導入另一個專門針對 goroutine 的東西:WaitGroup,根據 參考來源3 與其介紹原始代碼得知
修改為加入 WaitGroup 的版本:
// // version 4 資料邊蒐集編輸出
func doWorker4(id int, c chan int, wg *sync.WaitGroup) {
// for n := range c {
// fmt.Printf("Worker %d received %c \n", id, n)
// // done <- true // 刪除
wg.Done()
// }
// }
// type worker4 struct {
// in chan int
wg *sync.WaitGroup
// }
func createWorker4(id int, wg *sync.WaitGroup) worker4 {
// w := worker4{
// in: make(chan int),
wg: wg,
// }
go doWorker4(id, w.in, wg)
// return w
// }
// func chanDemo4() {
var wg sync.WaitGroup
// var workers [10]worker4
// for i := 0; i < 10; i++ {
workers[i] = createWorker4(i, &wg)
// }
wg.Add(20)
// for i, worker := range workers {
// worker.in <- 'a' + i // send
// }
// // for i := 0; i < 10; i++ { // 刪除
// // <-workers[i].done // receive // 刪除
// // } // 刪除
// for i, worker := range workers {
// worker.in <- 'A' + i
// }
// // for i := 0; i < 10; i++ { // 刪除
// // <-workers[i].done // receive // 刪除
// // } // 刪除
wg.Wait()
// }
輸出結果為:
Worker 0 received a
Worker 0 received A
Worker 1 received b
Worker 1 received B
Worker 9 received j
Worker 2 received c
Worker 2 received C
Worker 3 received d
Worker 4 received e
Worker 4 received E
Worker 3 received D
Worker 6 received g
Worker 7 received h
Worker 8 received i
Worker 5 received f
Worker 5 received F
Worker 9 received J
Worker 7 received H
Worker 6 received G
Worker 8 received I
如此一來可以看到大小寫混在一起,表示他是邊搜集邊輸出。
但其中值得注意的是,在使用 WaitGroup 要注意 Add(數量) 中的數量必須與 groutine 開的數量一樣,否則都會引發 panic
fatal error: all goroutines are asleep - deadlock!
panic: sync: negative WaitGroup counter
https://github.com/luckyuho/ithome30-golang/tree/main/day15