-1
votes

Comment envoyer et obtenir des demandes où n> 10 URL

J'essaie de faire n obtenir des demandes de n, mais mon code fonctionne pour 8 URL, mais 10 Toujours pile sans problème.

Je suis nouveau à parcourir, je ne peux pas comprendre le problème. P> J'essaie d'écrire une application pour battre l'application .NET avec la même tâche. P>

Pourriez-vous suggérer ce qui ne va pas? P>

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
    //"bufio"
    "time"
)

type HttpResponse struct {
    url      string
    response *http.Response
    err      error
}

func main() {
    fmt.Println("Hello, world3.")

    var urls []string = []string{
    "www.webmagnat.ro",
    "nickelfreesolutions.com",
    "scheepvaarttelefoongids.nl",
    "tursan.net",
    "plannersanonymous.com",
    "saltstack.com",
    "deconsquad.com",
    "migom.com",
    "tjprc.org",
    "worklife.dk",
    "food-hub.org"}

    start := time.Now()
    results := asyncHttpGets(urls)

    f, err := os.Create("test.txt")
    if err != nil {
        fmt.Println(err)
        return
    }


    for _, result := range results {
        fmt.Printf("%s status: %s\n", result.url,
            result.response.Status)

            l, err := f.WriteString(result.url+"\n")
            if err != nil {
                fmt.Println(err)
                f.Close()
                return
            }
            _ = l
    }
    t := time.Now()
    elapsed := t.Sub(start)
    fmt.Printf("Ellipsed: %s\n", elapsed)

    err = f.Close()
    if err != nil {
        fmt.Println(err)
        return
    }


    fmt.Println("Buy, world2.")
}


func asyncHttpGets(urls []string) []*HttpResponse {
    ch := make(chan *HttpResponse, len(urls)) // buffered
    responses := []*HttpResponse{}
    for _, url := range urls {
         go func(url string) {
            fmt.Printf("Fetching %s \n", url)
            resp, err := http.Get("http://" + url)
            if err != nil {
                fmt.Printf("Failed to fetch %s\n", err)
                return
            }
            defer resp.Body.Close()

            if resp.StatusCode == http.StatusOK {
                fmt.Printf("HTTP Response Status : %v", resp.StatusCode)
                bodyBytes, err := ioutil.ReadAll(resp.Body)
                if err != nil {
                    log.Fatal(err)
                }
                bodyString := string(bodyBytes)

                fmt.Printf("HTTP Response Content Length : %v\n", len(bodyString))
            }

            ch <- &HttpResponse{url, resp, err}
        }(url)
    }

    for {
        select {
        case r := <-ch:
            fmt.Printf("%s was fetched\n", r.url)
            responses = append(responses, r)
            if len(responses) == len(urls) {
                return responses
            }
        case <-time.After(50 * time.Millisecond):
            fmt.Printf(".")
        }
    }

    return responses

}   


0 commentaires

4 Réponses :


-1
votes

Vous devez ajouter la construction de groupe d'attente, car lorsque deux threads exécutent, le fil principal se termine. Voir: https://yourbasic.org/golang/wait-for-goroutines-waitgroup / xxx


2 commentaires

Cela ne fonctionne pas, il a coincé à un endroit. Vous ne pouvez pas voir où utilisez-vous wg.done


@Mediator Il n'y a aucun moyen de faire le travail pour vous. J'ai souligné des problèmes avec la raison et j'ai fourni un lien avec un exemple de WG



-1
votes

Vous pouvez utiliser la bibliothèque suivante:

demandes : une bibliothèque de go pour réduire les maux de tête lors de la création de demandes HTTP (20k / s req)

https://github.com/alessiosavi/request

C'est développé pour résoudre le à de nombreux fichiers ouverts traiter avec des demandes parallèles.

L'idée est d'allouer une liste de demande, que de les envoyer avec un facteur "parallèle" configurable qui permettent de Exécuter uniquement la demande "n" à l'heure.

initialiser les demandes (vous avez déjà un ensemble d'URL) xxx

à ce stade, nous avons une liste contenant les demandes qui doivent être envoyé. Envoyons-les en parallèle! xxx

Vous pouvez trouver un exemple d'utilisation dans exemple dossier du référentiel.

spoiler < BlockQuote Classe = "Spoiler">

je suis l'auteur de cette petite bibliothèque


0 commentaires

1
votes

Le premier problème ici est que vous ne retournez pas de réponse dans le cas d'une erreur, le len (réponses) == len (URL) est susceptible de ne jamais correspondre, forçant votre boucle pour continuer pour toujours.

Démarrer en ajoutant un sync.waitgroup pour les demandes concurrentes xxx

alors vous pouvez aller sur les réponses jusqu'à ce que tout Les goroutines exceptionnelles sont effectuées xxx

Vous devez alors décider de la manière de gérer les réponses, allez-vous les lire dans l'appel concomitant ou renvoyer leur corps non lié. Puisque vous voudrez toujours tenter de consommer les corps si vous souhaitez réutiliser la connexion et que vous avez différé le corps .frose () , ceci actuellement doit arriver dans le même appel de la fonction. Vous pouvez soit modifier le type httpreesponse pour rendre cela possible, ou remplacer le respect.body avec un tampon contenant la réponse.

enfin que vous voudrez enfin avoir une sorte de délai d'attente pour le client (probablement à l'aide d'un contexte ) et placez une limite sur le nombre des demandes concurrentes étant faites.


4 commentaires

Ça marche. Merci. Mais ne fonctionne toujours pas avec N> 1000.


@Mediator, c'est pourquoi j'ai dit que vous devez limiter la concurrence et que vous assurer des demandes peut trop


Oui, j'ai trouvé une solution Github.com/remeh/sizedwaitgroup mais ne fonctionne toujours pas pour 1000 demande et 8 la taille de la limite de la piscine ne peut pas fonctionner aussi. Maintenant, j'ai un problème étrange '2020/02/11 10:44:19 EOF inattendu'


@Mediator: Ce n'est pas vraiment lié aux problèmes de concurrence que vous avez montrés ici. Une connexion inopinément fermée pour une raison quelconque, mais ce n'est pas quelque chose que nous pouvons diagnostiquer de cet exemple.



1
votes

Le problème est que vous retournez en cas d'erreur sans écrire sur le canal. Voir votre si err! = Nil {retour} code> instruction. Parce que vous n'écrivez pas à la chaîne, le len (réponses) == len (URL) code> L'instruction ne peut jamais être vraie.

 go func(url string) {
            fmt.Printf("Fetching %s \n", url)
            resp, err := http.Get("http://" + url)
            if err != nil {
                fmt.Printf("Failed to fetch %s\n", err)
                return
            }
            defer resp.Body.Close()

            if resp.StatusCode == http.StatusOK {
                fmt.Printf("HTTP Response Status : %v", resp.StatusCode)
                bodyBytes, err := ioutil.ReadAll(resp.Body)
                if err != nil {
                    log.Fatal(err)
                }
                bodyString := string(bodyBytes)

                fmt.Printf("HTTP Response Content Length : %v\n", len(bodyString))
            }

            ch <- &HttpResponse{url, resp, err}
        }(url)


0 commentaires