web-dev-qa-db-fra.com

Essayer d'exécuter plusieurs requêtes HTTP en parallèle, mais étant limité par Windows (registre)

Je développe une application (winforms C # .NET 4.0) où j'accède à une fonctionnalité de recherche depuis un tiers via une simple requête HTTP. J'appelle une URL avec un paramètre, et en retour j'obtiens une petite chaîne avec le résultat de la recherche. Assez simple.

Le défi est cependant que je dois faire beaucoup de ces recherches (quelques milliers), et je voudrais limiter le temps nécessaire. Par conséquent, je voudrais exécuter des demandes en parallèle (disons 10-20). J'utilise un ThreadPool pour ce faire, et la version courte de mon code ressemble à ceci:

public void startAsyncLookup(Action<LookupResult> returnLookupResult)
{
    this.returnLookupResult = returnLookupResult;

    foreach (string number in numbersToLookup)
    {
        ThreadPool.QueueUserWorkItem(lookupNumber, number);
    }
}

public void lookupNumber(Object threadContext)
{
    string numberToLookup = (string)threadContext;
    string url = @"http://some.url.com/?number=" + numberToLookup;
    WebClient webClient = new WebClient();
    Stream responseData = webClient.OpenRead(url);
    LookupResult lookupResult = parseLookupResult(responseData);

    returnLookupResult(lookupResult);
}

Je remplis numbersToLookup (un List<String>) d'un autre endroit, appelez startAsyncLookup et fournissez-lui une fonction de rappel returnLookupResult pour retourner chaque résultat. Cela fonctionne, mais j'ai constaté que je n'obtenais pas le débit souhaité.

Au début, je pensais que ce pourrait être la troisième partie ayant un système pauvre de leur côté, mais j'ai exclu cela en essayant d'exécuter le même code à partir de deux machines différentes en même temps. Chacun des deux a pris autant de temps qu'un seul, donc je pouvais exclure celui-là.

Un collègue m'a alors indiqué que cela pourrait être une limitation dans Windows. J'ai googlé un peu et trouvé entre autres ce post disant que par défaut Windows limite le nombre de requêtes simultanées au même serveur web à 4 pour HTTP 1.0 et à 2 pour HTTP 1.1 (pour HTTP 1.1 ce est en fait conforme à la spécification (RFC2068)).

Le même poste mentionné ci-dessus a également fourni un moyen d'augmenter ces limites. En ajoutant deux valeurs de registre à [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings] (MaxConnectionsPerServer et MaxConnectionsPer1_0Server), je pouvais contrôler cela moi-même.

Donc, j'ai essayé cela (assis tous les deux à 20), redémarré mon ordinateur et essayé de réexécuter mon programme. Malheureusement, cela n'a semblé aider personne. J'ai également gardé un œil sur le moniteur de ressources ( voir capture d'écran ) lors de l'exécution de ma recherche par lots, et j'ai remarqué que mon application (celle dont le titre était noirci) n'utilisait toujours que deux TCP.

Alors, la question est, pourquoi cela ne fonctionne-t-il pas? Le message auquel je suis lié utilise-t-il les mauvaises valeurs de registre? N'est-il pas possible de "pirater" plus longtemps sous Windows (je suis sous Windows 7)?

Toutes les idées seraient très appréciées :)

Et juste au cas où quelqu'un se demanderait, j'ai également essayé avec différents paramètres pour MaxThreads sur ThreadPool (de 10 à 100), et cela ne semble pas du tout affecter mon débit, donc le problème ne devrait pas être là non plus.

62
Julian

Il s'agit de ServicePoint . Qui fournit la gestion des connexions pour les connexions HTTP. Le nombre maximal par défaut de connexions simultanées autorisées par un objet ServicePoint est 2. Par conséquent, si vous devez l'augmenter, vous pouvez utiliser la propriété ServicePointManager.DefaultConnectionLimit . Vérifiez simplement le lien dans MSDN où vous pouvez voir un exemple. Et définissez la valeur dont vous avez besoin.

95
Incognito

Pour une référence plus rapide pour quelqu'un. Pour augmenter la limite de connexion par hôte, vous pouvez le faire dans votre Main () ou à tout moment avant de commencer à effectuer les requêtes HTTP.

   System.Net.ServicePointManager.DefaultConnectionLimit = 1000; //or some other number > 4
28
Matt

Tirez et oubliez cette méthode de votre méthode principale. L'utilisateur Icognito a raison, seuls 2 threads sont autorisés à jouer en même temps.

private static void openServicePoint()
{
    ServicePointManager.UseNagleAlgorithm = true;
    ServicePointManager.Expect100Continue = true;
    ServicePointManager.CheckCertificateRevocationList = true;
    ServicePointManager.DefaultConnectionLimit = 10000;
    Uri MS = new Uri("http://My awesome web site");
    ServicePoint servicePoint = ServicePointManager.FindServicePoint(MS);
}
2
George Papatheodorou

Pour Internet Explorer 8: exécutez l'Éditeur du Registre et accédez à la clé suivante HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_MAXCONNECTION SPERSERVER

et

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_MAXCONNECTION SPER1_0SERVER

Si FEATURE_MAXCONNECTIONSPERSERVER et FEATURE_MAXCONNECTIONSPER1_0SERVER sont manquants, créez-les. Créez maintenant une valeur DWORD appelée iexplore.exe pour les deux sous-clés (répertoriées ci-dessus) et définissez leur valeur sur 10 ou sur le nombre souhaité.

0
Gary