1. 程式人生 > >用syc.WaitGroup來等待go協程執行完畢

用syc.WaitGroup來等待go協程執行完畢

        看程式:

package main

import (
	"fmt"
	"time"
)

func print(i int) {
	time.Sleep(1e9)
	fmt.Println(i)
}

func main() {
	for i := 0; i < 10; i++ {
		go func(n int) {
			print(n)
		}(i)
	}
}

         結果沒有任何輸出,因為主協程很快退出了。

         等待一下,變為:

package main

import (
	"fmt"
	"time"
)

func print(i int) {
	time.Sleep(1e9)
	fmt.Println(i)
}

func main() {
	for i := 0; i < 10; i++ {
		go func(n int) {
			print(n)
		}(i)
	}

	for {}
}

         結果:

7
9
3
4
5
8
0
6
1
2

 

       這種等待太傻了, 改為:

package main

import (
	"fmt"
	"sync"
	"time"
)

func print(i int) {
	time.Sleep(1e9)
	fmt.Println(i)
}

func main() {
	var wg sync.WaitGroup

	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func(n int) {
			defer wg.Add(-1)  // same: defer wg.Done()
			print(n)
		}(i)
	}

	wg.Wait() 
}


         結果:

8
1
5
0
9
4
7
2
6
3

       分析一下wg.Wait執行等待操作, 直到wg的計數變為0才返回。 在上面例子中,Add(1)了10次, 然後Add(-1)了10次,剛好。 我們把程式變一下:

package main

import (
	"fmt"
	"sync"
	"time"
)

func print(i int) {
	time.Sleep(1e9)
	fmt.Println(i)
}

func main() {
	var wg sync.WaitGroup

	wg.Add(11)

	for i := 0; i < 10; i++ {
		go func(n int) {
			defer wg.Add(-1)  // same: defer wg.Done()
			print(n)
		}(i)
	}

	wg.Wait() 
}

        可以看到,計數達到11次,但只有10次的add(-1), 顯然wg.Wait永遠無法退出,提示:fatal error: all goroutines are asleep - deadlock!

        再看:

package main

import (
	"fmt"
	"sync"
	"time"
)

func print(i int) {
	time.Sleep(1e9)
	fmt.Println(i)
}

func main() {
	var wg sync.WaitGroup

	wg.Add(5)

	for i := 0; i < 10; i++ {
		go func(n int) {
			defer wg.Add(-1)  // same: defer wg.Done()
			print(n)
		}(i)
	}

	wg.Wait() 
}


        結果出錯,提示資訊:

panic: sync: WaitGroup is reused before previous Wait has returned

panic: sync: negative WaitGroup counter

        看到沒, negative counter了。

 

        不多說。