首頁  >  文章  >  後端開發  >  如何在 Go 中使用超時和重試來建立上下文?

如何在 Go 中使用超時和重試來建立上下文?

PHPz
PHPz轉載
2024-02-08 23:20:19671瀏覽

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

php小編新一將為大家介紹如何在Go語言中使用超時和重試來建立上下文。在編寫程式碼時,我們經常會遇到需要限制某個操作的執行時間或在操作失敗時進行重試的情況。 Go語言提供了一種簡潔而強大的機制,即上下文(context),它可以幫助我們實現這些需求。透過合理地利用超時和重試機制,我們可以提高程式碼的可靠性和穩定性,同時提升使用者體驗。在接下來的文章中,我們將詳細討論如何在Go語言中使用超時和重試來建立上下文。

問題內容

我嘗試在 go 中使用超時和多次重試來建立上下文。 這是程式碼範例

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
            }
        }
    }
}

然後,我呼叫 readretry result := readretry(port, 2, 5) // 2 秒逾時,5 次重試。但如果第一次資料還沒準備好,那麼 reader 無法寫入 rcvch 。可能已經滿了?為什麼?如果我嘗試在 readwithcontext 執行結束時關閉通道,則會發生衝突 - 寫入已關閉的通道。碰撞在哪裡?它認為,readwithcontext每次都會作為一個新實例啟動,創建一個rcvch的新實例,如果reader因超時而關閉,則所有鏈函數及其局部變數(包括通道)已被破壞。但是,看來我犯了一個錯誤。那麼,如何進行重試呢? 看看日誌是什麼樣子的:

IN READ RETRY
Read attempt: 1
IN readWithContext
Opening channel
IN reader
Start reader
Received: 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0d //<- data is received, but not written to the channel!!
reader: context cancelled

解決方法

每次重試都會建立一個新的閱讀器和一個新的頻道。如果 readWithContext 超時,讀者仍然在那裡等待,並且可能最終會閱讀,但現在通道的另一端沒有人在監聽,因此讀者被洩露。

有一個 reader goroutine 和一個通道,使用 readWithContext 從中讀取。如果上下文過期並且所有重試都用盡,您也必須停止讀取器。

以上是如何在 Go 中使用超時和重試來建立上下文?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除