ワーカープールパターン
並行実行数を制限します
「ワーカープールパターン」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。
ワーカープールとは
ワーカープールは、共有チャネルからジョブを取り出す一定数のゴルーチンを起動します。タスクごとにゴルーチンを1つ起動するのではなく、N個のワーカーを起動して作業を供給します。
- 同時に実行する処理数を制限する
- 何千ものゴルーチンを作成せずに再利用する
- データベースやAPIなどの共有リソースを保護する
並行性を制限する理由
ゴルーチンを無制限に起動すると、メモリやファイルディスクリプターを使い果たしたり、下流のサービスに過剰な負荷をかけたりする可能性があります。プールを使えば、一度に実行する作業量を制御できます。
取得するURLが10000個あるとしても、HTTPリクエストを10000個同時に送信したいわけではありません。20個のワーカーからなるプールなら、適切な範囲に保てます。
jobsチャネル
ジョブはjobsチャネルに流し込みます。各ワーカーはfor rangeループでそこから読み取ります。チャネルが閉じられるとループが終了し、ワーカーも終了します。
jobs := make(chan int, 100)
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)単一のワーカー
ワーカーは、jobsチャネルをrangeする関数にすぎません。各ジョブを処理し、結果をresultsチャネルに書き込みます。
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
results <- j * 2
}
}複数のワーカーを起動する
単純なループでプールを起動します。各反復で、同じワーカー関数を実行するゴルーチンを1つ起動します。すべてのワーカーが同じjobsチャネルとresultsチャネルを共有します。
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}方向付きチャネル型
ワーカーのシグネチャにある<-chan int(受信専用)とchan<- int(送信専用)に注目してください。これらの方向付き型により、ワーカーが誤ってjobsに送信したり、resultsから読み取ったりするのをコンパイラーが防げます。
結果を収集する
すべてのジョブを送り、チャネルを閉じた後、メインのゴルーチンはジョブ数と同じ数の結果を読み取ります。これによりプログラムが早期終了しないよう同期できます。
sum := 0
for a := 1; a <= 5; a++ {
sum += <-results
}
fmt.Println("total:", sum)完全に実行できるプール
1つのプログラムにまとめた完全なパターンを見てみましょう。3つのワーカーが5つの数値を2倍にします。実行して合計を確認してください。
package main
import "fmt"
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
results <- j * 2
}
}
func main() {
jobs := make(chan int, 5)
results := make(chan int, 5)
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
total := 0
for a := 1; a <= 5; a++ {
total += <-results
}
fmt.Println("total:", total)
}バッファ付きとバッファなし
バッファ付きのjobsチャネルでは、バッファが満杯になるまで、プロデューサーはブロックせずに作業をキューに入れられます。バッファなしのチャネルでは受け渡しが必要になり、ワーカーの準備が整うまで送信がブロックされます。バッファリングにより、作業が急増するプロデューサーの負荷を平滑化できます。
プールサイズを選ぶ
CPUバウンドの処理では、プールサイズをruntime.NumCPU()に近づけます。I/Oバウンドの処理(ネットワークやディスク)では、ワーカーは計算ではなく待機に時間を使うため、もっと大きくできます。
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Println("CPUs:", runtime.NumCPU())
}ゴルーチンリークを避ける
close(jobs)を忘れると、ワーカーは空のチャネルで永遠にブロックし、リークします。すべての作業を送信し終えたら必ずjobsチャネルを閉じ、for rangeループを終了させてください。
クイックチェック
ワーカープールについての理解度を確認しましょう。
まとめ
ワーカープールパターンについて学びました。
- 共有の jobs チャネルから読み取るワーカーを固定数起動します
- 安全性のために方向付きチャネル型を使用します
- ワーカーを終了するには jobs チャネルを閉じます
- 結果を収集して処理の完了を同期します
- ワークロードの種類(CPU と IO)に応じてプールのサイズを決めます
よくある質問
「ワーカープールパターン」レッスンは無料ですか?
はい。「ワーカープールパターン」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。
「ワーカープールパターン」で何を学びますか?
並行実行数を制限します ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Go Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「ワーカープールパターン」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このGo Academyレッスンでコードを書いて実行できますか?
はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- ワーカープールパターン
- Fan-OutとFan-In
- パイプラインのステージ
- グレースフルシャットダウン