fan-out、fan-inパターン【Go】
タスクを複数のgoroutineに分割して、順序通りに処理させたい場合に利用します。
fan-inは、複数の入力を1つのchannelにまとめて受信するパターンです。
fan-outは、複数の関数(goroutine)が、1つのchannelから値を読み取り送信するパターンです。
fan-outはCPUに作業を分配するため、Workersパターンとも呼ばれます。
次の例では、producerとmulti2とmulti4、main関数をchannelを通して接続し、
複数の処理を並行に、かつタスク分割して順々に実行しています。
処理が終わったchannelは、closeしないとrangeループから抜けられずに、
deadlockを引き起こすため、注意が必要です。
func producer(first chan<- int) { // firstは送信専用 defer close(first) // closeしないとrageループがdeadlockを引き起こす for i := 0; i < 10; i++ { first <- i } } func multi2(first <-chan int, second chan<- int) { // firstは受信専用、secondは送信専用 defer close(second) // closeしないとrageループがdeadlockを引き起こす for v := range first { second <- v * 2 } } func multi4(second <-chan int, third chan<- int) { // secondは受信専用、thirdは送信専用 defer close(third) // closeしないとrageループがdeadlockを引き起こす for v := range second { third <- v * 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 v := range third { fmt.Println(v) } }
上記コードのなかで、func定義のchannel引数に「<-」が記載されていますが、
これによって、対象のchannelを、送受信どちらかの専用とすることができます。
1行見ただけで、そのchannelが何のためのchannelなのか分かるようになり、
コードの保守性が向上します。
このパターンに基づいて、処理を分割して開発することができれば、
メンテナンスのしやすさや、コードのわかりやすさにもつながるかと思います。
ゴルーチン、チャネルを利用した並行パターン / fujimisakari blog