チャネルを使用した Go ゴルーチンでタイムアウトを正しく実装するにはどうすればよいですか?

DDD
リリース: 2024-11-08 14:57:02
オリジナル
292 人が閲覧しました

How to Implement Timeouts Correctly in Go Goroutines with Channels?

Go でのチャネルでのタイムアウトの使用

Goroutine とチャネルは、Go での同時プログラミングのための強力なメカニズムを提供します。ただし、ゴルーチンでのタイムアウトの処理は難しい場合があります。

ゴルーチンとタイムアウトを使用して URL リストの到達可能性を確認するシナリオでは、タイムアウトが実行されない状況が発生する可能性があります。一部の URL は到達できません。

提供されたコードを分析してみましょう:

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
}
ログイン後にコピー

問題はチェック関数内にあります。 goroutine で time.Sleep を使用すると、現在の goroutine (この場合は check 関数を実行している goroutine) が一時停止されます。チェック関数が一時停止している間、外側のゴルーチン内の select ステートメントは引き続き実行を試みます。

この場合、select ステートメントの両方のブランチ (結果またはタイムアウトのチェック) は 4 の後に実行可能になります。チェックが戻ったときの秒数。ただし、両方のブランチが実行可能であるため、ランタイムはどちらかを実行することを選択でき、その結果常に true が返される可能性があります。

これを解決するには、次に示すように、チェック関数ごとに新しい goroutine を作成する必要があります。以下の修正されたコード:

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(time.Second):
                ch <- false
            }
        }(url)
    }
    return <-ch
}
ログイン後にコピー

この場合、チェック関数は別の goroutine で実行され、外部の goroutine が一時停止されず、タイムアウトが正しく実行されることが保証されます。

以上がチャネルを使用した Go ゴルーチンでタイムアウトを正しく実装するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート