go修行12日目 channelなど


## channel

```golang
package main

import "fmt"

// SlieceとChannelを扱う関数
func gorooutine1(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	// <- Channelに送信
	c <- sum
}

func main() {
	s := []int{1, 2, 3, 4, 5}
	// channel integerを扱う
	c := make(chan int)
	go gorooutine1(s, c)
	// <- c　でChannelから受け取るまで待機
	x := <-c
	fmt.Println(x)
}

```

```
15
```

### キューのような使い方

- 2つのチャンネルを並列実行しても2つの処理の実行を待つ

```golang

package main

import "fmt"

// SlieceとChannelを扱う関数
func gorooutine1(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	// <- Channelに送信
	c <- sum
}

func gorooutine2(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	// <- Channelに送信
	c <- sum
}

func main() {
	s := []int{1, 2, 3, 4, 5}
	// channel integerを扱う
	c := make(chan int)
	go gorooutine1(s, c)
	go gorooutine2(s, c)
	// <- c　でChannelから受け取るまで待機
	x := <-c
	fmt.Println(x)
	y := <-c
	fmt.Println(y)
}
```

```
15
15
```

## Bufferd channel

```golang

package main

import "fmt"

func main() {
	ch := make(chan int, 2)
	ch <- 100
	fmt.Println(len(ch))
	ch <- 200
	fmt.Println(len(ch))
	// rangeで呼び出す場合はcloseしないと次のChannelを呼ぼうとしてエラーになる
	close(ch)

	// forで1つづつ呼び出す
	for c := range ch {
		fmt.Println(c)
	}
}
```


```
1
2
100
200
```


## channelのrange、Close

```golang

package main

import "fmt"

func goroutine1(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
		c <- sum
	}
	// 処理完了後はcloseを入れる
	close(c)
}

func main() {
	s := []int{1, 2, 3, 4, 5}
	c := make(chan int, len(s))
	go goroutine1(s, c)
	// channelを１回ずつ呼び出す
	for i := range c {
		fmt.Println(i)
	}
}
```


```
1
3
6
10
15
```

### Producer Consumer

```golang

package main

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

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

func consumer(ch chan int, wg *sync.WaitGroup) {
	for i := range ch {
		func() {
			fmt.Println("process", i*1000)
			wg.Done()
		}()
	}
	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)
	time.Sleep(2 * time.Second)
	fmt.Println("Done")
}
```

```
process 0
process 4000
process 2000
process 6000
process 8000
process 10000
process 12000
process 14000
process 16000
process 18000
#################################
Done
```


## fan-out fan-in

```golang

package main

import "fmt"

func producer(first chan int) {
	defer close(first)
	for i := 0; i < 10; i++ {
		first <- i
	}
}

func multi2(first chan int, second chan int) {
	defer close(second)
	for i := range first {
		// 1 * 2 = 2
		// 2 * 2 = 4
		second <- i * 2
	}
}

func multi4(second chan int, third chan int) {
	defer close(third)
	for i := range second {
		// 2 * 4 = 8
		// 4 * 4 = 4
		third <- i * 4
	}
}

func main() {

	first := make(chan int)
	second := make(chan int)
	third := make(chan int)

	go producer(first)
	go multi2(first, second)
	go multi4(second, third)
	for result := range third {
		fmt.Println(result)
	}
}
```


```
0
8
16
24
32
40
48
56
64
72
```

## select 

```golang

package main

import (
	"fmt"
	"time"
)

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

func goroutine2(ch chan string) {
	for {
		ch <- "packat from 2"
		time.Sleep(1 * time.Second)
	}
}

func main() {
	c1 := make(chan string)
	c2 := make(chan string)
	go goroutine1(c1)
	go goroutine2(c2)

	for {
		select {
		case msg1 := <-c1:
			fmt.Println(msg1)
		case msg2 := <-c2:
			fmt.Println(msg2)
		}
	}
}
```

```
packat from 1
packat from 2
packat from 2
packat from 2
packat from 1
packat from 2
packat from 2
packat from 2
```

## Default Section

```golang

package main

import (
	"fmt"
	"time"
)

func main() {
	tick := time.Tick(100 * time.Millisecond)
	boom := time.After(500 * time.Millisecond)

	for {
		select {
		// 100Millisocond毎
		case <-tick:
			fmt.Println("tick,")
			// 500Millisocond毎
		case <-boom:
			fmt.Println("BOOM")
			// loop終了
			return
			// それ以外はピリオド
		default:
			fmt.Println("    .")
			time.Sleep(50 * time.Millisecond)
		}
	}
}
```

```
    .
    .
tick,
    .
    .
tick,
    .
    .
tick,
    .
    .
tick,
    .
    .
tick,
BOOM
```