酷!學園
技術討論區 => 程式討論版 => 主題作者是: Yamaka 於 2015-08-11 19:25
-
goroutine 有個現象,在 main() 建立 goroutine 後,如果這個函數還沒跑完,
main() 並不會等它結束後才結束整個程式,看個例子
package main
func main() {
var count int64 = 0
go func() {
for idx := 0; idx < 200; idx++ {
count++
}
}()
println(count)
}
執行結果:
$ go run ex041.go
0
for 迴圈根本就還沒跑到,整個程式就 game over
整理了幾個能讓 goroutine 確實跑完的方式
(1) 利用鍵盤輸入等待
import (
"fmt"
)
func main() {
var count int64 = 0
go func() {
for idx := 0; idx < 200; idx++ {
count++
}
}()
var in string
fmt.Scanln(&in)
println(count)
}
result:
200
雖然可行,不過迴圈如果要跑很久,會因為按鍵盤時間快慢,迴圈也有可能不會完全跑完
(2) 利用 channel
func main() {
var count int64 = 0
c1 := make(chan bool)
go func() {
for idx := 0; idx < 200; idx++ {
count++
}
c1 <- true
}()
<-c1
println(count)
}
channel 型態不定要 bool,任何資料型態都可以,整數、字串甚至 struct 也可以
type MyType struct {
ID int64
Name string
}
func main() {
var count int64 = 0
c1 := make(chan MyType)
go func() {
for idx := 0; idx < 200; idx++ {
count++
}
c1 <- MyType{}
}()
<-c1
println(count)
}
c1 目的只是要在接收資料時的等待效果。
(3) 使用 sync/WaitGroup
import (
"sync"
)
func main() {
var count int64 = 0
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for idx := 0; idx < 200; idx++ {
count++
}
}()
wg.Wait()
println(count)
}
這個就比較清楚了,在使用 go 之前先告訴系統有一個 goroutine 要等待它跑完
defer wg.Done() 這行是告訴系統『我跑完嘍』
方式 1,2 適合單一 goroutine 或是數量不多時,當 goroutine 數量很多
sync/WaitGroup 就很好用,wg.Wait()會等到所有 goroutine 都結束才放行