2010-12-02 51 views
10

J'ai besoin d'une requête Http que je peux utiliser dans .Net qui prend moins de 100 ms. Je suis capable d'y parvenir dans mon navigateur, donc je ne vois vraiment pas pourquoi c'est un problème de code.Comment obtenir une demande HTTP rapide .Net

J'ai essayé WinHTTP ainsi que WebRequest.Create et les deux sont plus de 500ms ce qui n'est pas acceptable pour mon cas d'utilisation.

Voici des exemples du test simple que j'essaie de faire passer. (WinHttpFetcher est un simple wrapper que j'ai écrit, mais il est l'exemple le plus trivial d'une demande Get que je ne suis pas sûr que ça vaut la peine de coller.)

J'obtiens des résultats acceptables avec LibCurlNet mais s'il y a des utilisations simultanées la classe I obtient une violation d'accès. De plus, comme ce n'est pas du code managé et qu'il doit être copié dans le répertoire bin, il n'est pas idéal de le déployer avec mon projet open source.

Des idées d'une autre implémentation à essayer?

[Test] 
    public void WinHttp_Should_Get_Html_Quickly() 
    { 
     var fetcher = new WinHttpFetcher(); 
     var startTime = DateTime.Now;   
     var result = fetcher.Fetch(new Uri("http://localhost")); 
     var endTime = DateTime.Now; 
     Assert.Less((endTime - startTime).TotalMilliseconds, 100); 
    } 
    [Test] 
    public void WebRequest_Should_Get_Html_Quickly() 
    { 
     var startTime = DateTime.Now; 
     var req = (HttpWebRequest) WebRequest.Create("http://localhost"); 
     var response = req.GetResponse(); 
     var endTime = DateTime.Now; 
     Assert.Less((endTime - startTime).TotalMilliseconds, 100); 
    } 
+0

Le problème n'est pas HttpWebRequest. Je reçois généralement des demandes dans environ 13ms se connectant à localhost. Êtes-vous sûr que ce n'est pas le serveur? –

Répondre

16

Lorsque l'analyse comparative, il est préférable de jeter au moins les deux premiers timings car ils sont susceptibles de fausser les résultats:

  • Période 1: Dominée par JIT frais généraux c'est-à-dire le processus de transformation du code en octets en code natif.
  • Moment 2: Un passage d'optimisation possible pour le code JIT'd.

Les temps après cela refléteront mieux les performances de répétition. Voici un exemple de faisceau de test qui ignorera automatiquement les passes JIT et d'optimisation, et exécutera un nombre d'itérations déterminé avant de prendre une moyenne pour affirmer les performances. Comme vous pouvez le voir, le passage JIT prend beaucoup de temps.

JIT: 410.79ms

Optimize: 0.98ms.

moyenne sur 10 itérations: 0.38ms

code:

[Test] 
public void WebRequest_Should_Get_Html_Quickly() 
{ 
    private const int TestIterations = 10; 
    private const int MaxMilliseconds = 100; 

    Action test =() => 
    { 
     WebRequest.Create("http://localhost/iisstart.htm").GetResponse(); 
    }; 

    AssertTimedTest(TestIterations, MaxMilliseconds, test); 
} 

private static void AssertTimedTest(int iterations, int maxMs, Action test) 
{ 
    double jit = Execute(test); //disregard jit pass 
    Console.WriteLine("JIT:{0:F2}ms.", jit); 

    double optimize = Execute(test); //disregard optimize pass 
    Console.WriteLine("Optimize:{0:F2}ms.", optimize); 

    double totalElapsed = 0; 
    for (int i = 0; i < iterations; i++) totalElapsed += Execute(test); 

    double averageMs = (totalElapsed/iterations); 
    Console.WriteLine("Average:{0:F2}ms.", averageMs); 
    Assert.Less(averageMs, maxMs, "Average elapsed test time."); 
} 

private static double Execute(Action action) 
{ 
    Stopwatch stopwatch = Stopwatch.StartNew(); 
    action(); 
    return stopwatch.Elapsed.TotalMilliseconds; 
} 
4

Utilisez la classe StopWatch pour obtenir les horaires précis. Ensuite, assurez-vous de ne pas voir les résultats de la compilation de code non optimisée ou JIT en exécutant votre test de synchronisation plusieurs fois dans le code de version. Rejeter les premiers appels pour enlever l'impact de JIT et ensuite prendre la bonne nouvelle du reste. VS.NET a la capacité de mesurer les performances, et vous pouvez également utiliser quelque chose comme Fiddler pour voir combien de temps vous passez "sur le fil" et la santé mentale vérifier que ce n'est pas votre serveur IIS/web qui cause les retards. 500ms est un temps très long, et il est possible d'être dans les 10s de ms avec ces classes, alors n'abandonnez pas l'espoir (pour l'instant).

Mise à jour # 1:

Ceci est un article qui parle de micro-analyse comparative et ce qui est nécessaire pour éviter de voir des choses comme JIT:

http://blogs.msdn.com/b/vancem/archive/2009/02/06/measureit-update-tool-for-doing-microbenchmarks.aspx

Vous n'êtes pas tout à fait micro- benchmarking, mais il y a beaucoup de bonnes pratiques ici.

Mise à jour # 2:

Alors, j'ai écrit cette application de la console (en utilisant VS.NET 2010) ...

class Program 
{ 
    static void Main(string[] args) 
    { 
     var stopwatch = Stopwatch.StartNew(); 
     var req = (HttpWebRequest)WebRequest.Create("http://localhost"); 
     var response = req.GetResponse(); 
     Console.WriteLine(stopwatch.ElapsedMilliseconds);    
    } 
} 

... et Ctrl-F5'd il. Il a été compilé en tant que débogage, mais je l'ai exécuté sans débogage, et j'ai obtenu 63ms. Je cours cela sur mon ordinateur portable Windows 7, et ainsi http://localhost ramène la page d'accueil IIS7 par défaut. Courir à nouveau je reçois des moments similaires.

Exécution d'une version Release donne fois dans le 50ms à 55ms gamme.

C'est l'ordre de grandeur que je m'attendrais. De toute évidence, si votre site Web exécute une recompilation ASP.NET, ou si le recyclage du pool d'applications est en cours, ou si vous effectuez un grand nombre de traitements back-end, vos horaires seront différents.Si votre balisage est massif, il sera également différent, mais aucune des classes que vous utilisez côté client ne devrait être la limitation du débit ici. Ce sera l'espoir du réseau et/ou le traitement de l'application à distance.

+1

+1 Jetez toujours au moins les deux premiers résultats qui seront JIT, puis peut-être un laissez-passer optimiser. –

+0

J'ai essayé plusieurs fois en mode release et c'est toujours lent. Je doute vraiment que le chronomètre ait une importance de plus de 30 ms, je crois que mes tests sont toujours valables. –

+0

Si vous êtes capable de produire dans les 10 de millisecondes avec ces classes, j'aimerais le voir. La seule façon que j'ai été capable de faire est de boucler et de faire la moyenne des résultats. Mais pour le cas d'utilisation je l'utilise pour la première requête est la seule qui compte, car sur chaque requête web du pool d'applications il le traite comme la première requête. –

1

Essayez de définir la propriété Proxy de l'instance HttpWebRequest sur null. Si cela fonctionne, essayez de le définir sur GlobalProxySelection.GetEmptyWebProxy(), ce qui semble être plus correct.

Vous pouvez lire à ce sujet ici mor: - WebRequest lent ?: http://holyhoehle.wordpress.com/2010/01/12/webrequest-slow/


Mise à jour 2018: Tirer cette place des commentaires.

System.Net.GlobalProxySelection est obsolète.Cette classe a été abandonnée. Veuillez utiliser WebRequest.DefaultWebProxy à la place pour accéder et définir le proxy par défaut global. Utilisez null au lieu de GetEmptyWebProxy(). - jirarium 22 juillet '17 à 5:44

+0

Je l'ai fait et cela n'affecte pas le temps de réponse –

+2

** System.Net.GlobalProxySelection ** est obsolète. Cette classe a été abandonnée. Veuillez utiliser ** WebRequest.DefaultWebProxy ** à la place pour accéder et définir le proxy global par défaut.Utilisez ** null ** au lieu de ** GetEmptyWebProxy() **. – jirarium