こんにちは。KOUKIです。
とあるWeb系企業で、Goエンジニアをやっています。
今回は、ChannelでFan In/Fan Outの実装を通じて、アルゴリズムを勉強しましょう。
<目次>
Fan In/Fan Out
Fan In/Fan Outでは、3つの登場人物が出てきます。
- Producer — データを提供する人
- Channel(ChA, ChB, ChC) — データを中継する人
- Consumer — データを消費する人
Fan In
Fan Inは、複数のキュー(ChA, ChB)を一つのデータ(Chc)にまとめるアルゴリズムです。
図で表すと以下のようになります。

アルゴリズムに直すと、次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
package main import ( "fmt" "math/rand" "time" ) func sleep() { time.Sleep(500 * time.Millisecond) } func producer(ch chan<- int, name string) { for { sleep() n := rand.Intn(100) fmt.Printf("Channel %s -> %d\n", name, n) ch <- n } } func consumer(ch <-chan int) { for n := range ch { fmt.Printf("<- %d\n", n) } } func fanIn(chA, chB <-chan int, chC chan<- int) { var n int for { select { case n = <-chA: chC <- n case n = <-chB: chC <- n } } } func main() { chA := make(chan int) chB := make(chan int) chC := make(chan int) go producer(chA, "A") go producer(chB, "B") go consumer(chC) fanIn(chA, chB, chC) } |
プログラムを実行してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
$ go run main.go Channel B -> 87 Channel A -> 81 <- 87 <- 81 Channel A -> 47 <- 47 Channel B -> 59 <- 59 Channel A -> 81 <- 81 Channel B -> 18 <- 18 Channel B -> 25 <- 25 Channel A -> 40 <- 40 Channel A -> 56 <- 56 Channel B -> 0 |
Fan Out
Fan Outは、一つのキュー(ChA)に対して、複数のワーカ(Consumer)がデータを処理をアルゴリズムです。
図で表すと以下のようになります。

アルゴリズムに直すと、次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
package main import ( "fmt" "math/rand" "time" ) func sleep() { time.Sleep(500 * time.Millisecond) } func producer(ch chan<- int) { for { sleep() n := rand.Intn(100) fmt.Printf(" -> %d\n", n) ch <- n } } func consumer(ch <-chan int, name string) { for n := range ch { fmt.Printf("Consumer %s <- %d\n", name, n) } } func fanOut(chA <-chan int, chB, chC chan<- int) { for n := range chA { if n < 50 { chB <- n } else { chC <- n } } } func main() { chA := make(chan int) chB := make(chan int) chC := make(chan int) go producer(chA) go consumer(chB, "B") go consumer(chC, "C") fanOut(chA, chB, chC) } |
プログラムを実行してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ go run main.go -> 81 Consumer C <- 81 -> 87 Consumer C <- 87 -> 47 Consumer B <- 47 -> 59 Consumer C <- 59 -> 81 Consumer C <- 81 -> 18 Consumer B <- 18 -> 25 Consumer B <- 25 -> 40 Consumer B <- 40 |
おわりに
Channelを使うと面白いコードが書けるようになります。
少し応用のパターンとして、パイプライン処理もおすすめです。
Goroutineは制御が大変ですが、とにかく便利です。
皆さんもぜひチャレンジしてくださいね!
それでは、また!
Go記事まとめ
ソースコード
Fan In
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
package main import ( "fmt" "math/rand" "time" ) func sleep() { time.Sleep(500 * time.Millisecond) } func producer(ch chan<- int, name string) { for { sleep() n := rand.Intn(100) fmt.Printf("Channel %s -> %d\n", name, n) ch <- n } } func consumer(ch <-chan int) { for n := range ch { fmt.Printf("<- %d\n", n) } } func fanIn(chA, chB <-chan int, chC chan<- int) { var n int for { select { case n = <-chA: chC <- n case n = <-chB: chC <- n } } } func main() { chA := make(chan int) chB := make(chan int) chC := make(chan int) go producer(chA, "A") go producer(chB, "B") go consumer(chC) fanIn(chA, chB, chC) } |
Fan Out
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
package main import ( "fmt" "math/rand" "time" ) func sleep() { time.Sleep(500 * time.Millisecond) } func producer(ch chan<- int) { for { sleep() n := rand.Intn(100) fmt.Printf(" -> %d\n", n) ch <- n } } func consumer(ch <-chan int, name string) { for n := range ch { fmt.Printf("Consumer %s <- %d\n", name, n) } } func fanOut(chA <-chan int, chB, chC chan<- int) { for n := range chA { if n < 50 { chB <- n } else { chC <- n } } } func main() { chA := make(chan int) chB := make(chan int) chC := make(chan int) go producer(chA) go consumer(chB, "B") go consumer(chC, "C") fanOut(chA, chB, chC) } |
コメントを残す
コメントを投稿するにはログインしてください。