2010-06-02 20 views
58

Je développe une application (winforms C# .NET 4.0) dans laquelle j'accède à une fonctionnalité de recherche d'un tiers via une simple requête HTTP. J'appelle une url avec un paramètre, et en retour je reçois 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 courir des demandes en parallèle (disons 10-20). J'utilise un ThreadPool pour le faire, et la version courte de mon code ressemble à ceci:Essayer d'exécuter plusieurs requêtes HTTP en parallèle, mais en étant limité par Windows (registre)

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 remplirai numbersToLookup (un List<String>) d'un autre endroit, appelez startAsyncLookup et lui fournir une fonction de rappel returnLookupResult pour retourner chaque résultat. Cela fonctionne, mais j'ai constaté que je n'obtenais pas le débit que je veux. Au départ, je pensais que c'était peut-être la troisième partie qui avait un système défectueux de leur côté, mais j'ai exclu ceci en essayant d'exécuter le même code à partir de deux machines différentes en même temps. Chacun des deux a pris aussi longtemps que l'un seul, donc je pourrais exclure celui-là. Un collègue m'a alors signalé que cela pourrait être une limitation dans Windows. J'ai googlé un peu, et trouvé parmi d'autres this 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 c'est en fait selon la spécification (RFC2068)).

Le même article 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_Server), je pourrais contrôler moi-même. Donc, j'ai essayé cela (assis à la fois à 20), redémarré mon ordinateur, et j'ai essayé d'exécuter à nouveau mon programme. Malheureusement, cela ne semblait pas aider. J'ai également gardé un œil sur le moniteur de ressources (see screen shot) lors de l'exécution de ma recherche de lot, et j'ai remarqué que mon application (celle avec le titre noirci) n'utilisait encore que deux connexions TCP. Donc, la question est: pourquoi cela ne fonctionne-t-il pas? Le message que j'ai lié à l'utilisation des valeurs de registre incorrectes? Est-ce que ce n'est peut-être plus possible de "bidouiller" sous Windows (je suis sur Windows 7)?

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

Et tout le monde juste au cas où devraient se demander, j'ai aussi essayé différents réglages pour MaxThreads sur ThreadPool (everyting de 10 à 100), et cela ne semblait pas affecter mon débit à tous, donc le problème ne devrait pas être là non plus.

+0

lien Capture d'écran donne http erreur 404 :( – RBT

+0

Est-ce que nous savons pourquoi il y a deux clés FEATURE_MAXCONNECTIONSPERSERVER et FEATURE_MAXCONNECTIONSPER1_0SERVER? Quelle est la signification de ces deux clés distinctes? Logiquement il devrait y avoir qu'un seul. – RBT

+0

post liés (pctools.com) n'existe plus – faintsignal

Répondre

92

Il est question de ServicePoint. Qui fournit la gestion de connexion pour les connexions HTTP. Le nombre maximal 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. Il suffit de vérifier le lien dans MSDN là vous pouvez voir un échantillon. Et définissez la valeur dont vous avez besoin.

+1

Merci, merci, merci :) C'était tout! – Nailuj

+0

Bienvenue;). Content que ça aide. – Incognito

+0

Merci à vous deux pour la bonne question et la réponse – kape123

0

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. Maintenant, créez une valeur DWORD appelée iexplore.exe pour les deux sous-clés (énumérées ci-dessus) et définissez leur valeur à 10 ou n'importe quel nombre désiré.

+0

Je n'arrive pas à comprendre pourquoi cela fonctionnerait, car cela ne fait que limiter les limites de IE, et pas en général ... Anywho, la réponse de Incognito a résolu mon problème – Nailuj

+0

Il ne devrait pas être iexplore. exe mais le nom de votre fichier exécutable et sa limite ne s'applique qu'aux connexions sortant du contrôle de WebBrowser –

27

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 les requêtes HTTP.

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

Feu et oubliez cette méthode à partir de votre méthode principale. L'utilisateur d'Icognito est correct, seulement 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); 
}