ホームページ  >  記事  >  バックエンド開発  >  Go でタイムアウトと再試行を使用してコンテキストを作成するにはどうすればよいですか?

Go でタイムアウトと再試行を使用してコンテキストを作成するにはどうすればよいですか?

PHPz
PHPz転載
2024-02-08 23:20:19715ブラウズ

如何在 Go 中使用超时和重试来创建上下文?

php editor Xinyi では、Go 言語でタイムアウトとリトライを使ってコンテキストを作成する方法を紹介します。コードを作成するとき、操作の実行時間を制限したり、操作が失敗したときに再試行する必要がある状況によく遭遇します。 Go 言語は、これらのニーズを達成するのに役立つ、シンプルかつ強力なメカニズム、コンテキストを提供します。タイムアウトと再試行メカニズムを適切に利用することで、ユーザー エクスペリエンスを向上させながら、コードの信頼性と安定性を向上させることができます。次の記事では、タイムアウトと再試行を使用して Go 言語でコンテキストを作成する方法について詳しく説明します。

質問内容

タイムアウトと複数の再試行を使用してgoでコンテキストを作成しようとしています。 コードサンプルは次のとおりです

リーリー

次に、 readretry を呼び出します。 result := readretry(port, 2, 5) // 2 秒のタイムアウト、5 回の再試行。ただし、初めてデータの準備ができていない場合、readerrcvch に書き込むことができません。もしかしたらいっぱいですか?なぜ? readwithcontext 実行の最後にチャネルを閉じようとすると、閉じられたチャネルへの書き込みという競合が発生します。衝突箇所はどこですか? readwithcontext が毎回新しいインスタンスとして開始され、rcvch の新しいインスタンスが作成されると考えられます。タイムアウトにより reader が閉じられると、すべてのチェーンが機能します。ローカル変数 (チャネルを含む) が破棄されています。しかし、どうやら私は間違いを犯したようです。それで、どうやって再試行するのでしょうか? ログがどのようになるかを確認してください:

func readretry(port io.readwritecloser, timeout, cnt int) []byte {
    fmt.println("in read retry")
    for i := 0; i < cnt; i++ {
        fmt.println("read attempt:", i)
        res := readwithcontext(timeout, port)
        if res != nil {
            return res
        }
    }
    return nil
}

func readwithcontext(timeout int, port io.readwritecloser) []byte {
    fmt.println("in readwithcontext")
    fmt.println("opening channel")
    rcvch := make(chan []byte)
    ctx, cancel := context.withtimeout(context.background(), time.duration(time.second*time.duration(timeout)))
    defer cancel()

    go reader(ctx, port, rcvch)

    for {
        select {
        case <-ctx.done():
            fmt.println("reader: context cancelled")
            return nil
        case buf := <-rcvch:
            fmt.println("reader: got data")
            return buf
        }
    }
}

func reader(ctx context.context, port io.readwritecloser, rcvch chan []byte) {

    fmt.println("in reader")

    answ := make([]byte, 1024)
    buf := bytes.buffer{}
    var err error

    for {
        i := 0
        i, err = port.read(answ)
        if err != nil && err != io.eof {
            log.printf("port.read: %v", err)
        }
        if i != 0 {
            answ = answ[:i]
            buf.write(answ)
            if buf.bytes()[len(buf.bytes())-1] == delimiter {
                fmt.print("received: ")
                printbuf(buf.bytes())
                rcvch <- buf.bytes() //if there is no data in the first attempt, cannot write to the channel here!!
                return
            }
        }
    }
}

回避策

再試行するたびに、新しいリーダーと新しいチャネルが作成されます。 readWithContext がタイムアウトした場合、リーダーはまだそこで待機しており、最終的には読み取る可能性がありますが、チャネルの反対側で誰も聞いていないため、リーダーはリークされます。

reader goroutine とチャネルを用意し、readWithContext を使用してそこから読み取ります。コンテキストの有効期限が切れてすべての再試行が使い果たされた場合も、リーダーを停止する必要があります。

以上がGo でタイムアウトと再試行を使用してコンテキストを作成するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はstackoverflow.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。