Limite de concurrence sur HttpWebRequest

J’écris une application pour mesurer la vitesse à laquelle je peux télécharger des pages Web en C #. Je fournis une liste de noms de domaine uniques, puis je génère un nombre X de threads et exécute HTTPWebRequests jusqu’à ce que la liste des domaines soit épuisée. Le problème est que peu importe le nombre de threads que j’utilise, je ne reçois qu’environ 3 pages par seconde.

J’ai découvert que System.Net.ServicePointManager.DefaultConnectionLimit valait 2, mais j’avais l’impression que cela était lié au nombre de connexions par domaine. Étant donné que chaque domaine de la liste est unique, cela ne devrait pas poser de problème.

Ensuite, j’ai découvert que la méthode GetResponse () bloque l’access à tous les autres processus jusqu’à la fermeture de WebResponse: http://www.codeproject.com/KB/IP/Crawler.aspx#WebRequest . Je n’ai trouvé aucune autre information sur le Web pour sauvegarder cette revendication, cependant, j’ai implémenté une requête HTTP en utilisant des sockets, et j’ai remarqué une accélération significative (4x à 6x).

Alors, mes questions: est-ce que quelqu’un sait exactement comment fonctionnent les objects HttpWebRequest?, Existe-t-il une solution de contournement à ce qui a été mentionné ci-dessus?

Avez-vous essayé d’utiliser les méthodes asynchrones telles que BeginGetResponse ()?

Si vous utilisez .net 4.0, vous voudrez peut-être essayer ce code. J’utilise essentiellement Tasks pour effectuer 1000 requêtes sur un site spécifique (je l’utilise pour effectuer des tests de charge d’application sur ma machine de développement et je ne vois aucune limite en tant que telle, car mon application voit ces demandes de manière successive).

public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { for (int i = 0; i < 1000; i++) { var webRequest = WebRequest.Create(textBox1.Text); webRequest.GetReponseAsync().ContinueWith(t => { if (t.Exception == null) { using (var sr = new StreamReader(t.Result.GetResponseStream())) { ssortingng str = sr.ReadToEnd(); } } else System.Diagnostics.Debug.WriteLine(t.Exception.InnerException.Message); }); } } } public static class WebRequestExtensions { public static Task GetReponseAsync(this WebRequest request) { return Task.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null); } } 

Étant donné que la charge de travail ici est liée aux E / S, il n’est pas nécessaire de créer des threads pour effectuer le travail, ce qui peut nuire aux performances. L’utilisation des méthodes asynchrones sur la classe WebClient utilise des ports de complétion E / S et sera donc beaucoup plus performante et consumra moins de ressources.

Vous devriez utiliser la méthode BeginGetResponse qui ne bloque pas et qui est asynchrone.

Lorsque vous traitez avec une asynchronie liée aux E / S, le fait que un thread soit chargé de faire le travail d’E / S rest bloqué en attendant que le matériel (dans ce cas la carte réseau) réponde. Si vous utilisez la version intégrée de BeginGetResponse, le thread la mettra en queue sur la carte réseau et sera alors disponible pour effectuer davantage de travail. Lorsque le matériel est terminé, il vous avertit et votre rappel est appelé.

Je voudrais noter que la méthode BeginGetResponse n’est pas complètement asynchrone: (à partir de MSDN )

La méthode BeginGetResponse nécessite certaines tâches d’installation synchrones (résolution DNS, détection de proxy et connexion de socket TCP, par exemple) avant que cette méthode ne devienne asynchrone. Par conséquent, cette méthode ne doit jamais être appelée sur un thread d’interface utilisateur, car elle peut prendre un certain temps, généralement plusieurs secondes.