2010-12-02 10 views
10

Necesito una solicitud Http que pueda usar en .Net, que lleva menos de 100 ms. Puedo lograr esto en mi navegador, así que realmente no veo por qué este es un problema en el código.Cómo obtener una solicitud de .Net Http rápida

He intentado WinHTTP así como WebRequest.Create y ambos son más de 500ms que no es aceptable para mi caso de uso.

Aquí hay ejemplos de la prueba simple que intento pasar. (WinHttpFetcher es un contenedor simple que escribí pero hace el ejemplo más trivial de una solicitud de obtención que no estoy seguro de que valga la pena pegar)

Estoy obteniendo resultados aceptables con LibCurlNet pero si hay usos simultáneos del clase obtengo una infracción de acceso. Además, dado que no se trata de código administrado y debe copiarse en el directorio bin, no es ideal para implementar con mi proyecto de código abierto.

¿Alguna idea de otra implementación para probar?

[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

El problema no es HttpWebRequest. Normalmente recibo solicitudes en aproximadamente 13 ms conectando con localhost. ¿Estás seguro de que no es el servidor? –

Respuesta

16

Cuando la evaluación comparativa, es mejor para descartar al menos los primeros dos tiempos, ya que son propensos a sesgar los resultados:

  • Timing 1: Dominado por encima de la cabeza JIT es decir, el proceso de convertir el código de bytes en código nativo.
  • Temporización 2: una posible pasada de optimización para el código JIT.

Los tiempos posteriores a esto reflejarán un rendimiento de repetición mucho mejor.

El siguiente es un ejemplo de un arnés de prueba que omitirá automáticamente las pasadas JIT y de optimización, y ejecutará una prueba un número determinado de iteraciones antes de tomar un promedio para afirmar el rendimiento. Como puede ver, el pase JIT requiere una cantidad sustancial de tiempo.

JIT: 410.79ms

Optimizar: 0.98ms.

media de más de 10 iteraciones: 0.38ms

Código:

[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

Utilice la clase StopWatch para obtener sincronizaciones precisas.

Luego, asegúrese de que no está viendo los resultados del código no optimizado o la compilación JIT al ejecutar su prueba de tiempo varias veces en el código de la versión. Deseche las primeras llamadas para eliminar el impacto de JIT y luego tome las malas noticias del resto.

VS.NET tiene la capacidad de medir el rendimiento, y es posible que también desee utilizar algo como Fiddler para ver cuánto tiempo está gastando "en el cable" y comprobar que no es su servidor IIS/web el que causa los retrasos.

500ms es un tiempo muy largo, y es posible estar en los 10s de ms con estas clases, así que no pierdas la esperanza (todavía).

Actualización # 1:

Esto es un gran artículo que habla de la evaluación comparativa micro y lo que se necesita para evitar ver cosas como JIT:

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

Usted no es bastante micro benchmarking, pero hay muchas mejores prácticas aquí.

Actualización # 2:

Así, escribí esta aplicación consola (con 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);    
    } 
} 

... y Ctrl-F5'd ella. Fue compilado como depuración, pero lo ejecuté sin depuración, y obtuve 63ms. Estoy ejecutando esto en mi computadora portátil con Windows 7, por lo que http://localhost devuelve la página de inicio predeterminada de IIS7. Ejecutando nuevamente me da tiempos similares.

Ejecutando una versión de lanzamiento da tiempos en el 50ms a 55ms rango.

Este es el orden de magnitud que esperaría. Claramente, si su sitio web está realizando una recompilación de ASP.NET, o reciclando el grupo de aplicaciones, o haciendo un montón de procesamiento de fondo, entonces sus tiempos serán diferentes.Si su marcado es masiva, también diferirá, pero ninguna de las clases que está usando en el lado del cliente debe ser la que limita los pasos aquí. Será la esperanza de la red y/o el procesamiento remoto de la aplicación.

+1

+1 Siempre deseche al menos los primeros dos resultados que serán JIT, luego tal vez un pase de optimización. –

+0

Lo he intentado en el modo de lanzamiento muchas veces y todavía es lento. Realmente dudo si el cronómetro va a importar en un orden de magnitud de más de 30 ms o más, creo que mis pruebas siguen siendo válidas. –

+0

Si puede producir en los 10 de milisegundos con estas clases, me encantaría verlo. La única forma en que he podido hacer esto es repetir y promediar los resultados. Pero para el caso de uso que estoy usando para la primera solicitud es el único que importa, porque en cada solicitud web del grupo de aplicaciones lo trata como la primera solicitud. –

1

Intente establecer la propiedad Proxy de la instancia HttpWebRequest en nulo. Si eso funciona, intente configurarlo en GlobalProxySelection.GetEmptyWebProxy(), que parece ser más correcto.

Usted puede leer sobre ello aquí mor: - WebRequest lenta ?: http://holyhoehle.wordpress.com/2010/01/12/webrequest-slow/


Actualización 2018: Tirando de esto a partir de los comentarios.

System.Net.GlobalProxySelection está obsoleto. Esta clase ha quedado obsoleta. Utilice WebRequest.DefaultWebProxy para acceder y configurar el proxy global predeterminado. Use null en lugar de GetEmptyWebProxy(). - jirarium 22 Jul '17 a 05:44

+0

He hecho esto y no afecta el tiempo de respuesta –

+2

** System.Net.GlobalProxySelection ** está obsoleto. Esta clase ha quedado en desuso. Utilice ** WebRequest.DefaultWebProxy ** para acceder y configurar el proxy global predeterminado.Use ** null ** en lugar de ** GetEmptyWebProxy() **. – jirarium

Cuestiones relacionadas