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)

 

 

 

 

 

 

 

 

 

 

 

2021/03,江端さんの技術メモ

Posted by ebata