Maison  >  Article  >  développement back-end  >  À propos de l'avenir/promesse à Golang

À propos de l'avenir/promesse à Golang

藏色散人
藏色散人avant
2021-04-15 14:33:522736parcourir

Ce qui suit est une introduction à Future/Promise in Golang de la colonne tutorielle golang. J'espère que cela sera utile aux amis dans le besoin !

À propos de l'avenir/promesse à Golang

De nos jours, le goulot d'étranglement le plus courant dans l'exécution des applications concerne les requêtes réseau. La requête réseau ne prend que quelques millisecondes, mais l’attente de la réponse est cent fois plus longue. Ainsi, si vous effectuez plusieurs requêtes réseau, les exécuter toutes en parallèle est la meilleure option pour réduire la latence. Future/Promise est l’un des moyens d’atteindre cet objectif.

Un futur signifie que vous avez besoin de quelque chose "dans le futur" (généralement le résultat d'une requête réseau), mais vous devez lancer une telle requête maintenant, et la requête sera exécutée de manière asynchrone. Ou pour le dire autrement, vous devez effectuer une requête asynchrone en arrière-plan.

Le modèle Future/Promise a des implémentations correspondantes dans plusieurs langues. Par exemple, ES2015 a Promise et async-await, Scala a intégré Future et enfin, Golang a goroutine et canal pour réaliser des fonctions similaires. Une implémentation simple est donnée ci-dessous.

//RequestFuture, http request promise.
func RequestFuture(url string) <-chan []byte {
    c := make(chan []byte, 1)
    go func() {
        var body []byte
        defer func() {
            c <- body
        }()

        res, err := http.Get(url)
        if err != nil {
            return
        }
        defer res.Body.Close()

        body, _ = ioutil.ReadAll(res.Body)
    }()

    return c
}

func main() {
  future := RequestFuture("https://api.github.com/users/octocat/orgs")
  body := <-future
  log.Printf("reponse length: %d", len(body))
}

RequestFutureLa méthode renvoie un canal À l'heure actuelle, la requête http s'exécute toujours de manière asynchrone en arrière-plan goroutine. La méthode principale peut continuer à exécuter d'autres codes, comme déclencher d'autres Future, etc. Lorsque des résultats sont nécessaires, nous devons lire les résultats du canal. Si la requête http n'est pas renvoyée, la goroutine actuelle sera bloquée jusqu'à ce que le résultat soit renvoyé.

Cependant, la méthode ci-dessus présente encore certaines limites. L'erreur ne peut pas être retournée. Dans l'exemple ci-dessus, si une erreur se produit dans la requête http, la valeur de body sera nulle/vide. Cependant, comme le canal ne peut renvoyer qu’une seule valeur, vous devez créer une structure distincte pour envelopper les deux résultats renvoyés.

Résultat après modification :

// RequestFutureV2 return value and error
func RequestFutureV2(url string) func() ([]byte, error) {
    var body []byte
    var err error

    c := make(chan struct{}, 1)
    go func() {
        defer close(c)

        var res *http.Response
        res, err = http.Get(url)
        if err != nil {
            return
        }

        defer res.Body.Close()
        body, err = ioutil.ReadAll(res.Body)
    }()

    return func() ([]byte, error) {
        <-c
        return body, err
    }
}

Cette méthode renvoie deux résultats, résolvant les limitations de la première méthode. Lorsqu'elle est utilisée, elle ressemble à ceci :

func main() {
    futureV2 := RequestFutureV2("https://api.github.com/users/octocat/orgs")

    // not block
    log.Printf("V2 is this locked again")

    bodyV2, err := futureV2() // block
    if err == nil {
        log.Printf("V2 response length %d\n", len(bodyV2))
    } else {
        log.Printf("V2 error is %v\n", err)
    }
}

L'avantage de la modification ci-dessus est que la méthode futureV2() peut être appelée plusieurs fois. Et les deux peuvent renvoyer le même résultat.

Cependant, si vous souhaitez utiliser cette méthode pour implémenter de nombreuses fonctions asynchrones différentes, vous devez écrire beaucoup de code supplémentaire. Nous pouvons écrire une méthode util pour surmonter cette difficulté. Lorsque

// Future boilerplate method
func Future(f func() (interface{}, error)) func() (interface{}, error) {
    var result interface{}
    var err error

    c := make(chan struct{}, 1)
    go func() {
        defer close(c)
        result, err = f()
    }()

    return func() (interface{}, error) {
        <-c
        return result, err
    }
}

appelle la méthode Future, elle effectuera de nombreuses astuces de canal dans la pièce. Afin d'atteindre des objectifs universels, il existe une conversion de type de []buyte->interface{}->[]byte. Si une erreur se produit, une panique d'exécution sera déclenchée.

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