go routineの中からgo routineを起動してみる簡単な実験
まず、何も考えないで以下のプログラムを実行
// go run main2.go
package main
import (
"fmt"
)
func subPerson(i int) {
fmt.Printf("Now... sub_person(%v)\n", i)
}
func person(i int) {
fmt.Printf("Now... person(%v)\n", i)
go subPerson(i)
}
func main() {
for i := 0; i < 5; i++ {
go person(i)
}
}
当然、何も表示されれない。go routineが起動する前に、main()が終了してしまうから
なので、最後のスレッドが完了するまでは待機するようにする
// go run main2.go
package main
import (
"fmt"
"sync"
)
func subPerson(i int) {
fmt.Printf("Now... sub_person(%v)\n", i)
}
func person(i int, wg *sync.WaitGroup) {
defer wg.Done() // WaitGroupを最後に完了しないといけない。
fmt.Printf("Now... person(%v)\n", i)
go subPerson(i)
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1) // goルーチンを実行する関数分だけAddする
go person(i, &wg)
}
wg.Wait()
}
$ go run main2.go
Now... person(0)
Now... sub_person(0)
Now... person(4)
Now... sub_person(4)
Now... person(2)
Now... person(3)
Now... sub_person(3)
Now... person(1)
ただ、これの場合、subPerson()が実行されないまま終了することがある。例えば、、上記の場合、sub_person(1)が実施されずに終了してしまっている。
なので、subPerson()の終了を持って、main()の終了とするようにすると、こうなる。
// go run main2.go
package main
import (
"fmt"
"sync"
)
func subPerson(i int, wg *sync.WaitGroup) {
defer wg.Done() // WaitGroupを最後に完了しないといけない。
fmt.Printf("Now... sub_person(%v)\n", i)
}
func person(i int, wg *sync.WaitGroup) {
subWG := wg
//defer wg.Done() // WaitGroupを最後に完了しないといけない。
fmt.Printf("Now... person(%v)\n", i)
go subPerson(i, subWG)
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1) // goルーチンを実行する関数分だけAddする
go person(i, &wg)
}
wg.Wait()
}
結果は、以下の通りとなり、問題なし。
$ go run main2.go
Now... person(0)
Now... person(1)
Now... sub_person(1)
Now... person(4)
Now... sub_person(4)
Now... sub_person(0)
Now... person(2)
Now... sub_person(2)
Now... person(3)
Now... sub_person(3)