2010-12-02 6 views
10

Ich brauche eine HTTP-Anfrage, die ich in .Net verwenden kann, die unter 100 ms dauert. Ich kann das in meinem Browser erreichen, deshalb sehe ich wirklich nicht, warum das ein so großes Problem im Code ist.Wie bekomme ich eine Fast .Net Http Anfrage

Ich habe WinHTTP sowie WebRequest.Create versucht und beide sind über 500ms, die für meinen Anwendungsfall nicht akzeptabel ist.

Hier sind Beispiele für den einfachen Test, den ich versuche zu bestehen. (WinHttpFetcher ist ein einfacher Wrapper, den ich geschrieben habe, aber er macht das einfachste Beispiel einer Get-Anfrage, dass ich nicht sicher bin, dass es sich lohnt, einzufügen.)

Ich bekomme akzeptable Ergebnisse mit LibCurlNet, aber wenn es gleichzeitige Verwendungen der Klasse Ich bekomme eine Zugriffsverletzung. Da es sich nicht um verwalteten Code handelt und in das bin-Verzeichnis kopiert werden muss, ist es nicht ideal für die Bereitstellung mit meinem Open-Source-Projekt.

Irgendwelche Ideen einer anderen Implementierung zu versuchen?

[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

Das Problem ist nicht HttpWebRequest. Ich bekomme normalerweise Anfragen in ungefähr 13ms Verbindung zu localhost. Bist du sicher, dass es nicht der Server ist? –

Antwort

16

Wenn Benchmarking, ist es am besten, zumindest die ersten beiden Zeitpunkte zu verwerfen, da sie wahrscheinlich die Ergebnisse verzerren:

  • Timing-1: Dominiert von JIT-Overhead dh der Prozess, Byte-Code in nativen Code umzuwandeln.
  • Timing 2: Ein möglicher Optimierungsdurchlauf für den JIT'd-Code.

Timings danach wird die Wiederholungsleistung viel besser widerspiegeln.

Im Folgenden finden Sie ein Beispiel für eine Testumgebung, die automatisch JIT- und Optimierungsdurchläufe ignoriert und eine bestimmte Anzahl von Iterationen testet, bevor ein Durchschnittswert zur Leistungsüberprüfung verwendet wird. Wie Sie sehen können, benötigt der JIT-Pass sehr viel Zeit.

JIT: 410.79ms

Optimieren: 0.98ms.

Durchschnitt über 10 Iterationen: 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

Verwenden Sie die Klasse StopWatch, um genaue Zeiten zu erhalten.

Stellen Sie dann sicher, dass Sie die Ergebnisse des nicht optimierten Codes oder der JIT-Kompilierung nicht sehen, indem Sie Ihren Timing-Test mehrmals im Freigabecode ausführen. Verwerfen Sie die ersten paar Anrufe, um den Einfluss von JIT zu entfernen, und nehmen Sie dann die mittlere Nachricht des Rests.

VS.NET hat die Fähigkeit, Leistung zu messen, und Sie könnten auch etwas wie Fiddler verwenden, um zu sehen, wie viel Zeit Sie "auf dem Draht" verbringen und überprüfen, dass es nicht Ihr IIS/Webserver verursacht die Verzögerungen.

500ms ist eine sehr lange Zeit, und es ist möglich, mit diesen Klassen in den 10er ms zu sein, also gib die Hoffnung (noch) nicht auf.

Update # 1:

Dies ist ein großer Artikel, der über Micro-Benchmarking spricht und was nötig ist Dinge wie JIT nicht zu sehen:

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

Sie sind nicht ganz mikro- Benchmarking, aber hier gibt es viele Best Practices.

Update # 2:

Also schrieb ich diese Konsole app (mit 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);    
    } 
} 

... und Ctrl-F5'd es. Es wurde als Debug kompiliert, aber ich habe es ohne Debugging ausgeführt, und ich habe 63ms. Ich führe das auf meinem Windows 7 Laptop aus, und so bringt http://localhost die Standard-IIS7-Homepage zurück. Wenn ich es wieder laufe, bekomme ich ähnliche Zeiten.

Das Ausführen eines Release-Builds ergibt Zeiten im 50ms bis 55ms Bereich.

Dies ist die Größenordnung, die ich erwarten würde. Wenn Ihre Website eine ASP.NET-Neukompilierung durchführt oder den App-Pool recycelt oder viele Back-End-Prozesse durchführt, unterscheiden sich Ihre Timings eindeutig.Wenn Ihr Markup sehr umfangreich ist, wird es auch anders sein, aber keine der Klassen, die Sie auf der Client-Seite verwenden, sollte hier der geschwindigkeitsbestimmende Schritt sein. Es wird die Netzwerk-Hoffnung und/oder die Remote-App-Verarbeitung sein.

+1

+1 Werfen Sie immer mindestens die ersten beiden Ergebnisse weg, die JIT sind, dann vielleicht einen Optimierungsdurchgang. –

+0

Ich habe viele Male im Freigabemodus versucht und es ist immer noch langsam. Ich bezweifle wirklich, ob die Stoppuhr in der Größenordnung von mehr als 30 ms liegt. Ich glaube, dass meine Tests immer noch gültig sind. –

+0

Wenn Sie in der 10 von Millisekunden mit diesen Klassen produzieren können, würde ich es gerne sehen. Die einzige Möglichkeit, dies zu tun, ist die Schleife und Durchschnitt der Ergebnisse. Aber für den Anwendungsfall, den ich für die erste Anfrage verwende, ist der einzige, der zählt, denn auf jeder Web-Anfrage des Anwendungspools behandelt er sie wie die erste Anfrage. –

1

Versuchen Sie, die Proxy-Eigenschaft der HttpWebRequest-Instanz auf null zu setzen. Wenn das funktioniert, dann versuche es auf GlobalProxySelection.GetEmptyWebProxy() zu setzen, was korrekter scheint.

Sie können es lesen mor über hier: - WebRequest langsam ?: http://holyhoehle.wordpress.com/2010/01/12/webrequest-slow/


-Update 2018: Das Ziehen aus den Kommentaren auf.

System.Net.GlobalProxySelection ist veraltet. Diese Klasse ist veraltet. Verwenden Sie stattdessen WebRequest.DefaultWebProxy, um auf den globalen Standardproxy zuzugreifen und ihn festzulegen. Verwenden Sie null anstelle von GetEmptyWebProxy(). - jirarium 22. Juli '17 um 5:44

+0

Ich habe dies getan und es wirkt sich nicht auf die Antwortzeit –

+2

** System.Net.GlobalProxySelection ** ist veraltet.Diese Klasse wurde veraltet. Verwenden Sie stattdessen ** WebRequest.DefaultWebProxy **, um auf den globalen Standardproxy zuzugreifen und ihn festzulegen.Verwenden Sie ** null ** anstelle von ** GetEmptyWebProxy() **. – jirarium

Verwandte Themen