select 文
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 62/107。
select ステートメントを使用すると、goroutine は複数のチャネル操作を同時に待機できます。これは switch ステートメントに似ていますが、各 case にはチャネルの送信または受信が含まれます。複数のチャネルが準備できている場合、select はそのうち 1 つをランダムに選択します。
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() { ch1 <- "from channel 1" }()
go func() { ch2 <- "from channel 2" }()
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
}
}selectなしでは、ch1からの受信はデータが届くまでブロックされ、ch2のデータを取り逃す可能性があります。selectを使うと、先にデータを受信したチャンネルが処理されます。
default case によって、select は非ブロッキングになります。準備完了しているチャネルがない場合、すぐに実行されます。
select {
case msg := <-messages:
fmt.Println("Received:", msg)
default:
fmt.Println("No message available")
}一般的なパターンでは、select と time.After をタイムアウトと組み合わせます。time.After は、指定した時間が経過した後に値を受信するチャネルを返します。
select {
case result := <-ch:
fmt.Println("Got result:", result)
case <-time.After(2 * time.Second):
fmt.Println("Timeout!")
}これにより、チャネル操作が完了しない可能性がある場合に、プログラムが永遠に待機し続けるのを防げます。
チャレンジ
簡単select文を使用して複数の同時実行データソースを処理するサービスモニターを作成しましょう。モニターは異なるサービスチャネルを同時に監視し、データが到着したとき、または利用可能な更新がないときに適切に応答します。
コードを2つのファイルに分けて整理します。
monitor.go:selectベースのチャネル処理を使用して、サービス監視ロジックを定義します。Name(string)フィールドとStatus(string)フィールドを持つServiceUpdate構造体を作成します。3つのチャネル、
primary chan ServiceUpdate、backup chan ServiceUpdate、done chan boolを受け取るMonitor関数を実装します。この関数ではselectを使用して、3つすべてのチャネルを同時に監視します。primaryから受信した場合:整形した文字列Primary: [Name] is [Status]を返しますbackupから受信した場合:整形した文字列Backup: [Name] is [Status]を返しますdoneから受信した場合:Monitoring stoppedを返します
単一の
updates chan ServiceUpdateを受け取り、defaultケースを持つselectを使用してノンブロッキングチェックを実行するCheckStatus関数を実装します。- 更新が利用可能な場合:
Update available: [Name]を返します - 更新が利用可能でない場合(defaultケース):
No updates pendingを返します
main.go:チャネルを設定し、ブロッキングおよびノンブロッキングのselect動作を示します。実行するシナリオを決定するモードを入力から読み取ります:
primary、backup、stop、またはcheck。primary、backup、stopモードの場合:サービス名とステータスも読み取ります。3つのチャネルを作成し、モードに基づいて適切なチャネルにデータを送信するgoroutineを起動してから、Monitorを呼び出し、その結果を出力します。checkモードの場合:サービス名とステータスに加え、チェック前にデータを送信するかどうかを示すフラグ(sendまたはnosend)を読み取ります。capacity 1のbufferedチャネルを作成します。フラグがsendの場合は、CheckStatusを呼び出す前にチャネルへ更新を送信します。CheckStatusの結果を出力します。
次の入力が提供されます。
- 1行目:モード(
primary、backup、stop、またはcheck) - 2行目:サービス名
- 3行目:サービスステータス
- 4行目(
checkモードの場合のみ):sendまたはnosend
たとえば、次の入力が与えられた場合:
primary
Database
healthy出力は次のようになります。
Primary: Database is healthyまた、次の入力が与えられた場合:
check
Cache
active
nosend出力は次のようになります。
No updates pending自分で試してみよう
package main
import (
"fmt"
)
func main() {
var mode string
fmt.Scanln(&mode)
var serviceName string
fmt.Scanln(&serviceName)
var serviceStatus string
fmt.Scanln(&serviceStatus)
// TODO: 異なるモードを処理する: "primary", "backup", "stop", "check"
// モード "primary", "backup", "stop" の場合:
// - 3つのチャネルを作成する: primary, backup, done
// - 適切なチャネルにデータを送信する goroutine を起動する
// - Monitor を呼び出して結果を出力する
// モード "check" の場合:
// - 追加のフラグを読み取る ("send" または "nosend")
// - 容量 1 のバッファ付きチャネルを作成する
// - フラグが "send" の場合、チャネルに更新を送信する
// - CheckStatus を呼び出して結果を出力する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー自分で練習してみよう: Goオンラインコンパイラ