GO goroutineを玉入れ競争に例えて理解しようとする


## 玉入れ

田中君：1投あたり2秒
鈴木君：1投あたり1秒

ルール
- 先に10球投げた方の勝ち　→ ゲーム終了
- 玉入れ先は別々

ポイント
- waitするスレッドを1として、1つでも並列スレッドが完了した場合、プログラムを終了させる。


```go

package main

import (
	"fmt"
	"strconv"
	"sync"
	"time"
)

type Tomodachi struct {
	name           string
	per_throw_time int
	greeting       string
}

var greeting = "よろしくお願いします"

var tanaka = Tomodachi{
	name:           "tanaka",
	per_throw_time: 2,
	greeting:       greeting,
}

var suzuki = Tomodachi{
	name:           "suzuki",
	per_throw_time: 1,
	greeting:       greeting,
}

var wg = sync.WaitGroup{}

func main() {

	fmt.Printf("%vです。%v。\n", tanaka.name, greeting)
	fmt.Printf("%vです。%v。\n", suzuki.name, greeting)

	start_time := time.Now()
	// 待つスレッドの数
	wg.Add(1)
	go tamaire(tanaka.name, tanaka.per_throw_time)
	go tamaire(suzuki.name, suzuki.per_throw_time)

	fmt.Println("start")
	// スレッドから終わりの連絡を待つ。
	wg.Wait()
	// end_time := time.Now()

	elapsed_time := time.Since(start_time)

	fmt.Printf("経過時間 : %v\n", elapsed_time)
}

func tamaire(name string, per_throw_time int) {
	for i := 1; i < 100; i++ {
		time.Sleep(time.Duration(per_throw_time) * time.Second)
		if i == 10 {
			fmt.Printf("%v\n", time.Now())
			fmt.Printf("%v君%v投目\n", name, i)
			break
		}
		i := strconv.Itoa(i)
		fmt.Printf("%v\n", time.Now())
		fmt.Printf("%v君%v投目\n", name, i)

	}
	fmt.Printf("%v君の勝利!\n", name)
	// メインスレッドに「僕は終わったよ」と伝える。
	wg.Done()
}


```

実行結果

```

tanakaです。よろしくお願いします。
suzukiです。よろしくお願いします。
start
suzuki君1投目
tanaka君1投目
suzuki君2投目
suzuki君3投目
tanaka君2投目
suzuki君4投目
suzuki君5投目
tanaka君3投目
suzuki君6投目
suzuki君7投目
tanaka君4投目
suzuki君8投目
suzuki君9投目
tanaka君5投目
suzuki君10投目
suzuki君の勝利!
経過時間 : 10.0233975s


```

## 次に2人とも終了するまでゲームが終わらない場合

ポイント
- waitするスレッドを2とする。

```go

package main

import (
	"fmt"
	"strconv"
	"sync"
	"time"
)

type Tomodachi struct {
	name           string
	per_throw_time int
	greeting       string
}

var greeting = "よろしくお願いします"

var tanaka = Tomodachi{
	name:           "tanaka",
	per_throw_time: 2,
	greeting:       greeting,
}

var suzuki = Tomodachi{
	name:           "suzuki",
	per_throw_time: 1,
	greeting:       greeting,
}

var wg = sync.WaitGroup{}

func main() {

	fmt.Printf("%vです。%v。\n", tanaka.name, greeting)
	fmt.Printf("%vです。%v。\n", suzuki.name, greeting)

	start_time := time.Now()
	// 待つスレッドの数
	wg.Add(2)
	go tamaire(tanaka.name, tanaka.per_throw_time)
	go tamaire(suzuki.name, suzuki.per_throw_time)

	fmt.Println("start")
	// スレッドから終わりの連絡を待つ。
	wg.Wait()
	wg.Wait()
	// end_time := time.Now()

	elapsed_time := time.Since(start_time)

	fmt.Printf("経過時間 : %v\n", elapsed_time)
}

func tamaire(name string, per_throw_time int) {
	for i := 1; i < 100; i++ {
		time.Sleep(time.Duration(per_throw_time) * time.Second)
		if i == 10 {
			fmt.Printf("%v\n", time.Now())
			fmt.Printf("%v君%v投目\n", name, i)
			break
		}
		i := strconv.Itoa(i)
		fmt.Printf("%v\n", time.Now())
		fmt.Printf("%v君%v投目\n", name, i)

	}
	// fmt.Printf("%v君の勝利!\n", name)
	fmt.Printf("%v君終了!\n", name)
	// メインスレッドに「僕は終わったよ」と伝える。
	wg.Done()
}


```

終了結果

```

tanakaです。よろしくお願いします。
suzukiです。よろしくお願いします。
start
2021-12-26 00:29:47.9075919 +0900 JST m=+1.003917701
suzuki君1投目
2021-12-26 00:29:48.9075828 +0900 JST m=+2.003908601
tanaka君1投目
2021-12-26 00:29:48.9463528 +0900 JST m=+2.042678601
suzuki君2投目
2021-12-26 00:29:49.94648 +0900 JST m=+3.042805801
suzuki君3投目
2021-12-26 00:29:50.9080411 +0900 JST m=+4.004366901
tanaka君2投目
2021-12-26 00:29:50.9578967 +0900 JST m=+4.054222501
suzuki君4投目
2021-12-26 00:29:51.9588457 +0900 JST m=+5.055171501
suzuki君5投目
2021-12-26 00:29:52.9085968 +0900 JST m=+6.004922601
tanaka君3投目
2021-12-26 00:29:52.9710026 +0900 JST m=+6.067328401
suzuki君6投目
2021-12-26 00:29:53.9724243 +0900 JST m=+7.068750101
suzuki君7投目
2021-12-26 00:29:54.9105403 +0900 JST m=+8.006866101
tanaka君4投目
2021-12-26 00:29:54.973832 +0900 JST m=+8.070157801
suzuki君8投目
2021-12-26 00:29:55.9756013 +0900 JST m=+9.071927101
suzuki君9投目
2021-12-26 00:29:56.9254739 +0900 JST m=+10.021799701
tanaka君5投目
2021-12-26 00:29:56.9756559 +0900 JST m=+10.071981701
suzuki君10投目
suzuki君終了!
2021-12-26 00:29:58.9264477 +0900 JST m=+12.022773501
tanaka君6投目
2021-12-26 00:30:00.9271847 +0900 JST m=+14.023510501
tanaka君7投目
2021-12-26 00:30:02.9272481 +0900 JST m=+16.023573901
tanaka君8投目
2021-12-26 00:30:04.9276392 +0900 JST m=+18.023965001
tanaka君9投目
2021-12-26 00:30:06.9292777 +0900 JST m=+20.025603501
tanaka君10投目
tanaka君終了!
経過時間 : 20.0232072s

```

最後に念のため、wg.wait(0)した時の結果を確認

```go

package main

import (
	"fmt"
	"strconv"
	"sync"
	"time"
)

type Tomodachi struct {
	name           string
	per_throw_time int
	greeting       string
}

var greeting = "よろしくお願いします"

var tanaka = Tomodachi{
	name:           "tanaka",
	per_throw_time: 2,
	greeting:       greeting,
}

var suzuki = Tomodachi{
	name:           "suzuki",
	per_throw_time: 1,
	greeting:       greeting,
}

var wg = sync.WaitGroup{}

func main() {

	fmt.Printf("%vです。%v。\n", tanaka.name, greeting)
	fmt.Printf("%vです。%v。\n", suzuki.name, greeting)

	start_time := time.Now()
	// 待つスレッドの数
	wg.Add(0)
	go tamaire(tanaka.name, tanaka.per_throw_time)
	go tamaire(suzuki.name, suzuki.per_throw_time)

	fmt.Println("start")
	// スレッドから終わりの連絡を待つ。
	wg.Wait()
	wg.Wait()
	// end_time := time.Now()

	elapsed_time := time.Since(start_time)

	fmt.Printf("経過時間 : %v\n", elapsed_time)
}

func tamaire(name string, per_throw_time int) {
	for i := 1; i < 100; i++ {
		time.Sleep(time.Duration(per_throw_time) * time.Second)
		if i == 10 {
			fmt.Printf("%v\n", time.Now())
			fmt.Printf("%v君%v投目\n", name, i)
			break
		}
		i := strconv.Itoa(i)
		fmt.Printf("%v\n", time.Now())
		fmt.Printf("%v君%v投目\n", name, i)

	}
	// fmt.Printf("%v君の勝利!\n", name)
	fmt.Printf("%v君終了!\n", name)
	// メインスレッドに「僕は終わったよ」と伝える。
	wg.Done()
}


```

実行結果

```

tanakaです。よろしくお願いします。
suzukiです。よろしくお願いします。
start
経過時間 : 773.9µs


```

goroutineが始まる前にメインスレッドが終了。