こんにちは。KOUKIです。
とあるWeb系企業で、Goエンジニアをやっています。
今回は、Channelでワーカープールを実装しながらアルゴリズムを勉強しましょう。
<目次>
ワーカープールの概要
ワーカープールは、Producer(提供者)がChannelを通じて😀君(Worker)をプールに蓄積し、Channelを介してConsumer(消費者)に提供するアルゴリズムです。

Poolに😀君を貯めることで、手隙になったプロセスが順次処理できるといういい感じのプログラムを実装できます。
実装
In/Out Channel
まず、「Channel In」と「Channel Out」を定義しましょう。
1 2 3 4 5 6 7 8 9 10 11 |
package main import ( "fmt" "time" ) func main() { in := make(chan int) out := make(chan int) } |
Channelは上記の様にmakeを使って宣言します。int型の値を受信、送信できるようにしました。
Workerの作成
次に、Workerを作成しましょう。
1 2 3 4 5 6 7 |
func smaileWorker(in, out chan int) { for { n := <-in time.Sleep(500 * time.Millisecond) out <- n } } |
「inチャネルからデータを取得し、500ms待機してからoutチャネルに渡す」仕事を作成しました。
これは、main関数からgoroutineで呼び出しましょう。
1 2 3 4 5 6 7 |
func main() { ... // Workerを4つ作る for i := 0; i < 4; i++ { go smaileWorker(in, out) } } |
Producerの作成
次に、Producerを作成しましょう。
1 2 3 4 5 6 7 8 |
func produce(in chan<- int) { i := 0 for { fmt.Printf("-> Send job: %d\n", i) in <- i i++ } } |
このProducerは、Inチャネルにデータを送信し続けます。
これもmain関数からgoroutineで呼び出します。
1 2 3 4 5 |
unc main() { ... go produce(in) } |
Consumerの作成
最後に、Consumerを作成します。
1 2 3 4 5 |
func consume(out <-chan int) { for n := range out { fmt.Printf("<- Recv job: %d\n", n) } } |
Channelをrangeでループすると取り出すデータがない場合、データが入力されるまでプログラムをストップしてくれます。
これもmain関数から呼び出しましょう。
1 2 3 4 5 |
func main() { ... consume(out) } |
プログラムの実行
プログラムを実行しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
$ go run main.go -> Send job: 0 -> Send job: 1 -> Send job: 2 -> Send job: 3 -> Send job: 4 <- Recv job: 2 -> Send job: 5 <- Recv job: 0 <- Recv job: 1 <- Recv job: 3 -> Send job: 6 -> Send job: 7 -> Send job: 8 -> Send job: 9 <- Recv job: 5 <- Recv job: 6 <- Recv job: 4 <- Recv job: 7 -> Send job: 10 -> Send job: 11 -> Send job: 12 |
いい感じで、Send/Recvが出力されていますね。
おわりに
Channelの実用的なパターンとして、今回紹介した方法は大変意義があるものだと思います。
別のパターンとして、パイプライン処理もおすすめです。
かっこいいよく読みやすいプログラムを書くために、皆さんもぜひチャレンジしてくださいね!
それでは、また!
Go記事まとめ
ソースコード
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 |
package main import ( "fmt" "time" ) func smaileWorker(in, out chan int) { for { n := <-in time.Sleep(500 * time.Millisecond) out <- n } } func produce(in chan<- int) { i := 0 for { fmt.Printf("-> Send job: %d\n", i) in <- i i++ } } func consume(out <-chan int) { for n := range out { fmt.Printf("<- Recv job: %d\n", n) } } func main() { in := make(chan int) out := make(chan int) // Workerを4つ作る for i := 0; i < 4; i++ { go smaileWorker(in, out) } go produce(in) consume(out) } |
コメントを残す
コメントを投稿するにはログインしてください。