では、この関数をどのように実装すればよいでしょうか。その場合、select を使用してタイムアウトを設定できます。
select メカニズムはタイムアウト用に特別に設計されたものではありませんが、select の特徴は、いずれかのケースが完了している限り、他のケースの状況を考慮せずにプログラムが実行し続けることであるため、タイムアウトの問題を非常に便利に解決できます。ケース。
タイムアウト機構自体も、比較的高速なマシンや高速ネットワーク上で通常のプログラムを実行する場合などにいくつかの問題を引き起こしますが、低速なマシンやネットワーク上で実行すると問題が発生し、一貫性のない結果が生じます。デッドロック問題を解決することの価値は、それがもたらす問題よりもはるかに大きいのです。
select の使用法は switch 言語と非常によく似ており、select は新しい選択ブロックを開始し、各選択条件は case ステートメントで記述されます。
switch ステートメントと比較すると、select にはより多くの制限があります。最大の制限は、各 case ステートメントが IO 操作である必要があることです。一般的な構造は次のとおりです。
select {
case <-chan1:
case chan2 <- 1:
default:
}
select ステートメントでは、Go 言語は各送信ステートメントと受信ステートメントを最初から最後まで順番に評価します。
いずれかのステートメントが実行を継続できる (つまり、ブロックされていない) 場合は、それらの実行可能ステートメントのいずれかを選択して使用します。
どのステートメントも実行できない場合 (つまり、すべてのチャネルがブロックされている場合)、考えられる状況は 2 つあります。
- デフォルトのステートメントが指定されている場合は、デフォルトのステートメントが実行され、プログラムの実行は select ステートメントの後のステートメントから再開されます。
- デフォルト ステートメントがない場合、select ステートメントは少なくとも 1 つの通信が続行できるまでブロックされます。
サンプルコードは次のとおりです。
package main
import (
"fmt"
"time"
)
func main() {
channel := make(chan int)
close := make(chan bool)
//別のゴルーチンを開始
go func() {
for {
select {
case num:= <-channel:
fmt.Println("num = ", num)
case <-time.After(3 * time.Second):
fmt.Println("タイムアウト")
close <- true
}
}
}()
for i := 0; i < 5; i++ {
channel <- i
time.Sleep(time.Second)
}
<-close
fmt.Println("プログラム終了")
}
操作の結果は次のようになります。
num = 0
num = 1
num = 2
num = 3
num = 4