Goroutineのスロットリング
並行実行数を制御します
「Goroutineのスロットリング」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。
並行実行数の制限
1秒あたりの回数ではなく、同時に実行されるgoroutineの数を制限したい場合があります。これにより、タイミングに関係なく、リソースへの同時負荷を上限内に収められます。
- 並列実行数を制限します
- コネクションプールを保護します
- メモリ使用量の急増を防ぎます
セマフォとしてのチャネル
バッファ付きチャネルは、カウント型セマフォとして機能します。チャネルの容量が最大同時実行数になります。取得するときはトークンを送信し、解放するときはトークンを受信します。
sem := make(chan struct{}, 3)取得と解放
処理を開始する前にチャネルへ送信してスロットを取得します(チャネルが満杯ならブロックします)。処理が終わったら受信してスロットを解放し、別のgoroutineが使えるようにします。
sem <- struct{}{} // acquire
// do work
<-sem // releasestruct{}を使う理由
空の構造体struct{}{}は0バイトしか占有しません。チャネル要素にこれを使うと、無駄なメモリを使わない純粋なシグナルとしてセマフォを実装できます。
ループのスロットリング
タスクごとにgoroutineを起動しますが、それぞれの実行をセマフォで制御します。実際の処理を同時に行えるgoroutineは最大でcap個までで、残りは取得処理でブロックします。
for _, task := range tasks {
sem <- struct{}{}
go func(t Task) {
defer func() { <-sem }()
process(t)
}(t)
}WaitGroupとの組み合わせ
セマフォは同時実行数を制限しますが、すべての処理が終わったタイミングまでは知らせません。sync.WaitGroupと組み合わせて、すべてのタスクが終わるまで待機します。
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
defer func() { <-sem }()
process(t)
}()deferで解放
スロットは、処理がpanicした場合や早期にreturnした場合でも解放されるよう、必ずdeferで解放します。解放し忘れるとスロットがリークし、最終的に新しい取得処理がデッドロックします。
完全なスロットリング実行例
このプログラムは8個のタスクを実行し、同時実行数を最大2個に制限します。開始と終了を出力するため、制限が機能していることを確認できます。
package main
import (
"fmt"
"sync"
"time"
)
func main() {
sem := make(chan struct{}, 2)
var wg sync.WaitGroup
for i := 0; i < 8; i++ {
wg.Add(1)
sem <- struct{}{}
go func(id int) {
defer wg.Done()
defer func() { <-sem }()
fmt.Println("start", id)
time.Sleep(20 * time.Millisecond)
fmt.Println("end", id)
}(i)
}
wg.Wait()
fmt.Println("done")
}errgroupとSetLimit
golang.org/x/sync/errgroupパッケージには、グループの実行数を制限し、最初のエラーを伝播するSetLimitがあります。外部パッケージではありますが、多くの場合により簡潔な選択肢です。
スロットリングとワーカープールの比較
ワーカープールは、キューからタスクを取り出す固定数のgoroutineを再利用します。セマフォによるスロットリングはタスクごとにgoroutineを起動しますが、アクティブなgoroutine数に上限を設けます。タスク数が非常に多い場合はプールのほうが効率的で、セマフォのほうが後付けしやすく簡単です。
制限値の選び方
データベース呼び出しでは、接続プールのサイズ以下に制限値を設定します。外部HTTP通信では、ホストへの接続制限に合わせます。高すぎるとリソースを使い果たし、低すぎると容量を無駄にします。
クイックチェック
スロットリングに関する知識を確認しましょう。
振り返り
goroutineのスロットリングについて学びました。
- バッファ付きチャネルはカウント型セマフォとして機能する
- 送信で取得し、defer内の受信で解放する
- struct{}要素は0バイトしか消費しない
- WaitGroupと組み合わせて完了を待つ
- 保護するリソースに合わせて制限値を決める
AI チューターと学ぶ Go — 無料
ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。
- コース
- 51
- レッスン
- 203
よくある質問
「Goroutineのスロットリング」レッスンは無料ですか?
はい。「Goroutineのスロットリング」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。
「Goroutineのスロットリング」で何を学びますか?
並行実行数を制御します ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Go Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「Goroutineのスロットリング」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このGo Academyレッスンでコードを書いて実行できますか?
はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- トークンバケットの概念
- golang.org/x/time/rate
- Goroutineのスロットリング
- バックオフとリトライ