Maison  >  Article  >  développement back-end  >  Comment créer un contexte à l'aide de délais d'attente et de tentatives dans Go ?

Comment créer un contexte à l'aide de délais d'attente et de tentatives dans Go ?

PHPz
PHPzavant
2024-02-08 23:20:19671parcourir

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

l'éditeur php Xinyi vous présentera comment utiliser le délai d'attente et réessayer pour créer un contexte en langage Go. Lors de l'écriture de code, nous rencontrons souvent des situations dans lesquelles nous devons limiter le temps d'exécution d'une opération ou réessayer lorsque l'opération échoue. Le langage Go fournit un mécanisme simple et puissant, un contexte, qui peut nous aider à répondre à ces besoins. En utilisant correctement les mécanismes de délai d'attente et de nouvelle tentative, nous pouvons améliorer la fiabilité et la stabilité du code tout en améliorant l'expérience utilisateur. Dans le prochain article, nous verrons en détail comment utiliser les délais d'attente et les tentatives pour créer un contexte en langage Go.

Contenu de la question

J'essaie de créer un contexte en cours d'exécution en utilisant un délai d'attente et plusieurs tentatives. Voici l'exemple de code

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

Ensuite, j'appelle readretry result := readretry(port, 2, 5) // 2 secondes d'attente, 5 tentatives. Mais si les données ne sont pas prêtes la première fois, alors reader ne peut pas écrire sur rcvch . Peut-être qu'il est plein ? Pourquoi? Si j'essaie de fermer le canal à la fin de l'exécution de readwithcontext, un conflit se produit : l'écriture sur un canal fermé. Où est la collision ? Il pense que readwithcontext sera démarré comme une nouvelle instance à chaque fois, créant une nouvelle instance de rcvch, et si reader est fermé en raison d'un délai d'attente, toutes les fonctions de la chaîne et leurs variables locales (y compris les canaux) ont été détruites . Cependant, il semble que j'ai commis une erreur. Alors, comment réessayer ? Voyez à quoi ressemble le journal :

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

Solution de contournement

Chaque nouvelle tentative créera un nouveau lecteur et une nouvelle chaîne. Si readWithContext expire, le lecteur attend toujours et peut éventuellement lire, mais maintenant personne n'écoute à l'autre bout du canal, donc le lecteur est divulgué.

Il existe une goroutine reader et un canal pour lire à partir de l'utilisation reader goroutine 和一个通道,使用 readWithContext. Vous devez également arrêter le lecteur si le contexte expire et que toutes les tentatives sont épuisées.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer