用syc.WaitGroup來等待go協程執行完畢
阿新 • • 發佈:2018-11-17
看程式:
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了。
不多說。