Menu
Coddy logo textTech

select 文

CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 62/107。

select 文を使用すると、ゴルーチンは複数のチャネル操作を同時に待機できます。これは 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 ケースを使用すると、select は非ブロック(non-blocking)になります。準備ができているチャネルがない場合、即座に実行されます。

select {
case msg := <-messages:
    fmt.Println("Received:", msg)
default:
    fmt.Println("No message available")
}

一般的なパターンは、selecttime.After を使用したタイムアウトを組み合わせる方法です。time.After は、指定された時間の経過後に値を受信するチャネルを返します:

select {
case result := <-ch:
    fmt.Println("Got result:", result)
case <-time.After(2 * time.Second):
    fmt.Println("Timeout!")
}

これにより、チャネル操作が完了しない可能性がある場合に、プログラムが永遠に待ち続けるのを防ぐことができます。

challenge icon

チャレンジ

簡単

複数の並行データソースを処理するために select ステートメントを使用するサービスモニターを構築しましょう。このモニターは、異なるサービスチャネルを同時にリッスンし、データが到着したとき、または更新が利用できないときに適切に応答します。

コードは2つのファイルに分けて構成します:

  • monitor.go: selectベースのチャネル処理を使用して、サービス監視ロジックを定義します。

    Name (string) と Status (string) フィールドを持つ ServiceUpdate 構造体を作成します。

    3つのチャネル primary chan ServiceUpdatebackup 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 動作の両方を実演します。

    実行するシナリオ(primarybackupstop、または check)を決定するモードを入力から読み取ります。

    primarybackup、および stop モードの場合:サービス名とステータスも読み取ります。3つのチャネルを作成し、モードに基づいて適切なチャネルにデータを送信するゴルーチンを起動し、その後 Monitor を呼び出してその結果を出力します。

    check モードの場合:サービス名とステータス、およびチェック前にデータを送信するかどうかを示すフラグ(send または nosend)を読み取ります。容量1のバッファ付きチャネルを作成します。フラグが send の場合、CheckStatus を呼び出す前にチャネルに更新を送信します。CheckStatus の結果を出力します。

以下の入力が提供されます:

  • 1行目:モード(primarybackupstop、または check
  • 2行目:サービス名
  • 3行目:サービスステータス
  • 4行目(check モードのみ):send または nosend

例えば、以下が与えられた場合:

primary
Database
healthy

出力は以下のようになります:

Primary: Database is healthy

また、以下が与えられた場合:

check
Cache
active
nosend

出力は以下のようになります:

No updates pending

チートシート

select 文を使用すると、ゴルーチンは複数のチャネル操作を同時に待機できます。これは switch 文のように機能しますが、各 case はチャネルの送信または受信を伴います:

select {
case msg1 := <-ch1:
    fmt.Println(msg1)
case msg2 := <-ch2:
    fmt.Println(msg2)
}

複数のチャネルの準備ができている場合、select はランダムに1つを選択します。select がないと、1つのチャネルからの受信がブロックされ、別のチャネルのデータを逃す可能性があります。

default case を使用すると、select はノンブロッキングになります。どのチャネルの準備もできていない場合、即座に実行されます:

select {
case msg := <-messages:
    fmt.Println("Received:", msg)
default:
    fmt.Println("No message available")
}

一般的なパターンとして、selecttime.After を使用したタイムアウトの組み合わせがあります。time.After は、指定された時間の経過後に値を受信するチャネルを返します:

select {
case result := <-ch:
    fmt.Println("Got result:", result)
case <-time.After(2 * time.Second):
    fmt.Println("Timeout!")
}

これにより、チャネル操作が完了しない可能性がある場合に、プログラムが永遠に待機し続けるのを防ぐことができます。

自分で試してみよう

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)を作成する
	// - 適切なチャネルにデータを送信するゴルーチンを起動する
	// - Monitor を呼び出し、結果を出力する
	
	// モードが "check" の場合:
	// - 追加のフラグ("send" または "nosend")を読み取る
	// - キャパシティ1のバッファ付きチャネルを作成する
	// - フラグが "send" の場合、チャネルに更新を送信する
	// - CheckStatus を呼び出し、結果を出力する
	
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン