Go: チャネルでタイムアウトを使用する
Go では、タイムアウトとチャネルはゴルーチンの実行を制御し、その結果を同期する便利な方法を提供します。 。ただし、タイムアウト ケースが期待どおりに実行されない可能性がある特定のシナリオがあります。
問題ステートメント
次の Go コードを考えてみましょう:
import "fmt" import "time" func check(u string) bool { time.Sleep(4 * time.Second) return true } func IsReachable(urls []string) bool { ch := make(chan bool, 1) for _, url := range urls { go func(u string) { select { case ch <- check(u): case <-time.After(time.Second): ch <- false } }(url) } return <-ch } func main() { fmt.Println(IsReachable([]string{"url1"})) }
このコードの目的は、提供されたリスト内のすべての URL が到達可能かどうかを確認することです。 URL が 1 秒以内に応答しない場合、関数は false を返す必要があります。
ただし、このコードを実行すると、常に true が返されます。タイムアウト ケースは実行されません。
説明
この問題は、check(u) の実行方法が原因で発生します。 IsReachable 関数では、各ゴルーチンが check(u) を呼び出して URL の到達可能性をチェックします。ただし、check(u) は、現在のゴルーチン内で 4 秒間スリープしてから戻ります。
select ステートメント内では、case ch <- check(u): Branch が最初に使用可能になります。 u) はすでに戻ってきました。これにより、タイムアウト ケースが実行されなくなり、関数は常に true を返すことになります。
解決策
この問題を解決するには、check(u) 関数を実行する必要があります。別のゴルーチンで。これにより、select ステートメントがタイムアウトの場合を適切に処理できるようになります。
更新されたコードは次のとおりです:
import "fmt" import "time" func check(u string, checked chan<- bool) { time.Sleep(4 * time.Second) checked <- true } func IsReachable(urls []string) bool { ch := make(chan bool, 1) for _, url := range urls { go func(u string) { checked := make(chan bool) go check(u, checked) select { case ret := <-checked: ch <- ret case <-time.After(1 * time.Second): ch <- false } }(url) } return <-ch } func main() { fmt.Println(IsReachable([]string{"url1"})) }
これで、いずれかの URL が 1 秒以内に応答しなかった場合、関数は戻ります。間違い。さらに、使用可能な URL が 1 つだけの場合、関数は true を返します。
以上がこのチャネルの例で Go タイムアウトが機能しないのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。