要介紹 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