用syc.WaitGroup来等待go协程执行完毕

版权声明:本文为博主原创文章,转载时请务必注明本文地址, 禁止用于任何商业用途, 否则会用法律维权。 https://blog.csdn.net/stpeace/article/details/83921198

        看程序:

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了。

        不多说。

猜你喜欢

转载自blog.csdn.net/stpeace/article/details/83921198