サンプルによる Go: タイムアウト

外部リソースに接続するプログラムや、それ以外の方法で実行時間を制御する必要があるプログラムでは、タイムアウトが重要です。Go でタイムアウトを実装するのは、チャネルと select があるため、簡単でエレガントです。

package main
import (
    "fmt"
    "time"
)
func main() {

この例では、2 秒後にチャネル c1 に結果を返す外部呼び出しを実行しているとします。チャネルはバッファリングされているため、ゴルーチン内の送信は非ブロッキングであることに注意してください。これは、チャネルが読み取られない場合にゴルーチンのリークを防ぐための一般的なパターンです。

    c1 := make(chan string, 1)
    go func() {
        time.Sleep(2 * time.Second)
        c1 <- "result 1"
    }()

タイムアウトを実装する select を次に示します。res := <-c1 は結果を待って、<-time.After は 1 秒のタイムアウト後に値が送信されるのを待ちます。select は最初に準備ができた受信処理を実行するため、操作に許可された 1 秒を超えた場合はタイムアウトケースを使用します。

    select {
    case res := <-c1:
        fmt.Println(res)
    case <-time.After(1 * time.Second):
        fmt.Println("timeout 1")
    }

タイムアウトを 3 秒以上に長くすると、c2 からの受信が成功し、結果が出力されます。

    c2 := make(chan string, 1)
    go func() {
        time.Sleep(2 * time.Second)
        c2 <- "result 2"
    }()
    select {
    case res := <-c2:
        fmt.Println(res)
    case <-time.After(3 * time.Second):
        fmt.Println("timeout 2")
    }
}

このプログラムを実行すると、最初の操作がタイムアウトし、2 番目の操作が成功します。

$ go run timeouts.go 
timeout 1
result 2

次の例: 非ブロッキング チャネル操作