Maison > développement back-end > Golang > le corps du texte

À propos de l'avenir/promesse à Golang

藏色散人
Libérer: 2021-04-15 14:33:52
avant
2723 Les gens l'ont consulté

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))
}
Copier après la connexion

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
    }
}
Copier après la connexion

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)
    }
}
Copier après la connexion

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
    }
}
Copier après la connexion

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!

Étiquettes associées:
source:segmentfault.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal