【Golang】Goroutineまとめ

# Goroutineとは
並列処理のこと。他の言語だとマルチスレッドなどと言われる。

# 49 GoroutineとSync.WaitGroup
normal()とgoroutine()を並列で実行する場合、どちらかのメソッドにgoを頭につけて実行する。
```go
package main

import (
	"fmt"
	"time"
)

func goroutine(s string) {
	for i := 0; i < 5; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

func normal(s string) {
	for i := 0; i < 5; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

func main() {
	go goroutine("world")
	normal("hello")
}
```
```
hello
world
world
hello
hello
world
world
hello
hello
```
ここで、timeをコメントアウトするとnormal()の実行結果しか表示されない。
スレッドを生成し、goroutine()が実行される前にnormal()が終了してしまう
```go
package main

import (
	"fmt"
)

func goroutine(s string) {
	for i := 0; i < 5; i++ {
		// time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

func normal(s string) {
	for i := 0; i < 5; i++ {
		// time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

func main() {
	go goroutine("world")
	normal("hello")
}
```
```
hello
hello
hello
hello
hello

```
並列処理を実行するには以下のようにする。
```go
package main

import (
	"fmt"
	"sync"
)

func goroutine(s string, wg *sync.WaitGroup) {
	for i := 0; i < 5; i++ {
		fmt.Println(s)
	}
	wg.Done()
}

func normal(s string) {
	for i := 0; i < 5; i++ {
		fmt.Println(s)
	}
}

func main() {
	var wg sync.WaitGroup
	wg.Add(1)
	go goroutine("world", &wg)
	normal("hello")
	wg.Wait()
}
```
wgのAdd()で並列処理が一つあると宣言し、Wait()はDone()が実行されるまで終了しないという意味

# 50 channel
```go
package main

import (
	"fmt"
)

func goroutine1(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	c <- sum
}

func goroutine2(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	c <- sum
}

func normal(s string) {
	for i := 0; i < 5; i++ {
		fmt.Println(s)
	}
}

func main() {
	s := []int{1, 2, 3, 4, 5}
	c := make(chan int)
	go goroutine1(s, c)
	go goroutine2(s, c)
	x := <-c
	fmt.Println((x))
	y := <-c
	fmt.Println((y))
}
```
```
15
15
```
一つのチャネルを宣言し、goroutine1()とgoroutine2()にわたす。結果をチャネルに入れて帰ってきた値を変数に入れて出力する。

# 51 Buffered Channel
```go
package main

import (
	"fmt"
)

func main() {
	ch := make(chan int, 2)
	ch <- 100
	fmt.Println(len(ch))
	ch <- 200
	fmt.Println(len(ch))
	close(ch)

	for c := range ch {
		fmt.Println(c)
	}
}

```
channelを作成する際、make()の第２引数に数を指定するとchannelに入れられる数を指定することができる。
指定した数を超えてchannelに値を入れようとするとエラーになる。

また、chennelからforループで取り出す際、close()を実行しておかないとエラーになる。
これは、今回の例でいうと２つの値を取り出した後３つ目を取り出そうとしてしまうため。

# 53 producerとconsumer
ちょっと理解度浅い
生成したproducerとconsumerの間でchをやり取りし処理を実行している

```go
package main

import (
	"fmt"
	"sync"
)

func producer(ch chan int, i int) {
	ch <- i * 2
}

func consumer(ch chan int, wg *sync.WaitGroup) {
	for i := range ch {
		func() {
			wg.Done()
			fmt.Println("process", i*1000)
		}()
	}
	fmt.Println("##################")
}

func main() {
	var wg sync.WaitGroup
	ch := make(chan int)

	// Producer
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go producer(ch, i)
	}

	// Consumer
	go consumer(ch, &wg)
	wg.Wait()
	close(ch)
}
```

# 55 channelとselect
```go
package main

import (
	"fmt"
	"time"
)

func goroutine1(ch chan string) {
	for {
		ch <- "packet from 1"
		time.Sleep(3 * time.Second)
	}
}

func goroutine2(ch chan int) {
	for {
		ch <- 100
		time.Sleep(1 * time.Second)
	}
}

func main() {
	c1 := make(chan string)
	c2 := make(chan int)
	go goroutine1(c1)
	go goroutine2(c2)
	for {
		select {
		case msg1 := <-c1:
			fmt.Println(msg1)
		case msg2 := <-c2:
			fmt.Println(msg2)
		}
	}
}

```
別々のgoroutineで処理を実行し、それらの結果によって分岐させる場合はselectを使う

# 56 Default selectionとfor break
```go
package main

import (
	"fmt"
	"time"
)

func main() {
	tick := time.Tick(100 * time.Millisecond)
	boom := time.After(500 * time.Millisecond)
OuterLoop:
	for {
		select {
		case <-tick:
			fmt.Println("tick.")
		case <-boom:
			fmt.Println("BOOM")
			break OuterLoop
		default:
			fmt.Println("    .")
			time.Sleep(50 * time.Millisecond)
		}
	}
	fmt.Println("###############")
}

```
outerloopをforの外側に宣言し、breakの後に指定すると、breakでどのループを抜けるかを指定できる
time.Tickはchannelを返す