Go言語の並行処理デザインパターン by Rob Pike 前編

少し古いですが、[Rob Pikeの並行処理デザインパターンのビデオ](https://www.youtube.com/watch?v=f6kdp27TYZs)で取り上げられたコードまとめです。
オリジナルの[ソースコード]
(https://github.com/adityamenon/Google-IO_2012_Go-Concurrency-Patterns)はこちらで見れます。
## Generator ジェネレータ

```go:generator.go
package main

import (
	"fmt"
	"math/rand"
	"time"
	"runtime"
)

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	rand.Seed(time.Now().UnixNano())

	c := boring("boring!") // Function returning a channel.
	for i := 0; i < 5; i++ {
		fmt.Printf("You say: %q\n", <-c)
	}
	fmt.Println("You're boring: I'm leaving.")
}

func boring(msg string) <-chan string {
	c := make(chan string)
	go func() { // We launch the goroutine from inside the function.
		for i := 0; ; i++ {
			c <- fmt.Sprintf("%s %d", msg, i)
			time.Sleep(time.Duration(rand.Intn(10)) * time.Second)
		}

	}()
	return c // Return the channel to the caller.
}
```

`channel`はファーストクラスオブジェクトなので、関数の引数や、戻り値に使用できます。
boring関数内でチャネルを作り、goルーチンを使用し、for文の無限ループ内で、メイン関数に送信しています。
チャネルは同期処理なので、メイン側で受信されるまで、boring関数はブロックされます。
boring関数から、チャネルを返却し、メイン関数側へのコールバックに使用します。
乱数で一定時間wait処理を入れ、送受信が同期で処理されているのを分かりやすくしてます。
***
```go:generator2.go
func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	rand.Seed(time.Now().UnixNano())

	joe := boring("Joe") // Function returning a channel.
	ann := boring("Ann") // Function returning a channel.
	for i := 0; i < 5; i++ {
		fmt.Printf("You say: %q\n", <-joe)
		fmt.Printf("You say: %q\n", <-ann)
	}
	fmt.Println("You're boring: I'm leaving.")
}

func boring(msg string) <-chan string {
// 同じなので省略
```

この例では、boring関数を2回呼び出し、２つのチャネルを使用しています。boring関数をサービスとして使用しているとのことです。
JoeとAnnがペアで交互に実行されます。Annの方が先に処理を終えても、Joeの処理を待ちます。
次の例では、独立して実行させてみます。

***
## Multiplexing マルチプレクサ

```go:multiplexing.go
func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	rand.Seed(time.Now().UnixNano())

	c := fanIn(boring("Joe"), boring("Ann"))
	for i := 0; i < 10; i++ {
		fmt.Printf("You say: %q\n", <-c)
	}
	fmt.Println("You're boring: I'm leaving.")
}

func fanIn(input1, input2 <-chan string) <-chan string {
	c := make(chan string)
	go func() {
		for {
			c <- <-input1
		}
	}()
	go func() {
		for {
			c <- <-input2
		}
	}()
	return c
}

func boring(msg string) <-chan string {
// 同じなので省略
```
`boring`関数のチャネルを２つ引数に取る`fanIn`関数を定義してます。
内部でgoルーチンを使用して、それぞれ別のgoルーチンで独立して処理するようにしています。
これにより、先に処理が終わった方から、共通のチャネル`c`に送信するため、JoeとAnnが独立して実行されます。

#### 出力結果

```bash
You say: "Joe 0"
You say: "Ann 0"
You say: "Joe 1"
You say: "Ann 1"
You say: "Ann 2"
You say: "Ann 3"
You say: "Ann 4"
You say: "Joe 2"
You say: "Joe 3"
You say: "Ann 5"
You're boring: I'm leaving.

Process finished with exit code 0
```

***
## Select セレクト

```go:select.go
func fanIn(input1, input2 <-chan string) <-chan string {
	c := make(chan string)

	go func() {
		for {
			select {
			case s := <-input1:
				c <- s
			case s := <-input2:
				c <- s
			}
		}
	}()

	return c
}
```
先ほどのMultiplexingを、`select`で実装したものです。同じ動きになります。
goルーチン1つですっきりと書けます。

***
## Quit? 停止？
```go:quit.go
func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	rand.Seed(time.Now().UnixNano())

	quit := make(chan bool)
	c := boring("Joe", quit)

	for i := rand.Intn(10); i>=0; i-- {
		fmt.Println(<-c)
	}

	quit <- true // send a quit signal after a certain amount of time.
}

func boring(msg string, quit <-chan bool) <-chan string {
	c := make(chan string)
	go func() { // We launch the goroutine from inside the function.
		for i := 0; ; i++ {
			select {
			case c <- fmt.Sprintf("%s %d", msg, i):
			case <-quit:
				return // exit the for-loop.
			}
		}
	}()
	return c // Return the channel to the caller.
}
```
メイン関数からチャネルをboring関数に渡して、メイン関数からシグナルを送り、boring関数を停止させる例です。
もっともこの例では、メイン関数もすぐに終了してしまうので、次の例にて。。。

***
## RoundTrip ラウンドトリップ
```go:cleanup.go
func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	rand.Seed(time.Now().UnixNano())

	quit := make(chan bool)
	c := boring("Joe", quit)

	for i := rand.Intn(10); i >= 0; i-- {
		fmt.Println(<-c)
	}

	quit <- true // send a quit signal after a certain amount of time.

	fmt.Printf("Joe is done. %t", <-quit)
}

func boring(msg string, quit chan bool) <-chan string {
	c := make(chan string)
	go func() { // We launch the goroutine from inside the function.
		for i := 0; ; i++ {
			select {
			case c <- fmt.Sprintf("%s %d", msg, i):
			case <-quit:
				cleanup()
				quit <- true
				return // exit the for-loop.
			}
		}
	}()
	return c // Return the channel to the caller.
}

func cleanup() {
	// do clean up tasks...
}
```
`quit`チャネルを双方向通信で使用します。boring関数にて、リソースのクリーンナップ処理`cleanup()`をしてから、メイン関数にコールバックしてます。

[後編はこちら](http://qiita.com/tfutada/items/dc8db894ac270a79ef2b)