Go のチャネルでのタイムアウトの処理
問題:
ゴルーチンとチャネルを使用してURL のリストの到達可能性をチェックすると、タイムアウト条件が実行されないようです。この結果、一部の URL に到達できない場合でも、コードは常に true を返します。
分析:
問題は check(u) 関数の実装にあります。タイムアウトが実行されなくなります。コードでは、check(u) 関数が現在のゴルーチンで実行され、IsReachable の select ステートメントの実行がブロックされます。 select ステートメントのブロックが解除されるまでに、check(u) チャネルと time.After(time.Second) チャネルの両方を使用できるようになり、ランタイムはどちらかを選択できます。
1:
この問題に対処するには、別のゴルーチンで check(u) 関数を実行できます。
package main 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"})) }
この変更されたコードでは、check(u) 関数がゴルーチンで実行され、結果がチェックされたチャネルに渡されます。 IsReachable の select ステートメントは、チェックされたチャネルまたはタイムアウト チャネルの準備が整うまで待機するようになりました。これにより、タイムアウト条件が正しく処理されることが保証されます。
解決策 2:
または、すべての URL に単一のタイムアウトを設定してコードを簡素化することもできます。このアプローチは、ゴルーチンの作成に必要な時間に比べてタイムアウトが十分に長い場合に実現可能です。
package main import "fmt" import "time" func check(u string, ch chan<- bool) { time.Sleep(4 * time.Second) ch <- true } func IsReachable(urls []string) bool { ch := make(chan bool, len(urls)) for _, url := range urls { go check(url, ch) } time.AfterFunc(time.Second, func() { ch <- false }) return <-ch } func main() { fmt.Println(IsReachable([]string{"url1", "url2"})) }
このコードでは、time.AfterFunc を使用してすべての URL に単一のタイムアウトが設定されています。タイムアウト期間内にいずれかの URL に到達できる場合、ch チャネルは true を受け取り、関数は true を返します。それ以外の場合、false が ch に送信され、関数は false を返します。
以上がURL の到達可能性をチェックするときに、Go のチャネルでタイムアウトを適切に処理する方法は?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。