2010-03-08 6 views
5

Cuando envío/recepción de datos utilizando HttpWebRequest (en Silverlight) en pequeños bloques, mido la muy pequeño rendimiento de 500 bytes/s sobre una conexión de "localhost". Al enviar los datos en bloques grandes, obtengo 2 MB/s, que es un 5000 veces más rápido.¿Qué podría causar la gran sobrecarga de hacer una llamada a HttpWebRequest?

¿Alguien sabe lo que podría causar esta carga increíblemente grande?

Otros detalles:

  • estoy usando el método HTTP POST
  • hice la medición del rendimiento tanto en Firefox 3.6 e Internet Explorer 7. Ambos mostraron resultados similares.
  • Mi CPU se carga sólo el 10% (de cuatro núcleos, por lo que 40% en realidad)
  • WebClient mostró resultados similares
  • WCF/SOAP showed similar results

actualización: El código del lado del cliente Silverlight que uso es esencialmente mi propia implementación de la clase WebClient. La razón por la que lo escribí es porque noté el mismo problema de rendimiento con WebClient, y pensé que HttpWebRequest permitiría ajustar el problema de rendimiento. Lamentablemente, esto no funcionó. La implementación es la siguiente:

public class HttpCommChannel 
{ 
    public delegate void ResponseArrivedCallback(object requestContext, BinaryDataBuffer response); 

    public HttpCommChannel(ResponseArrivedCallback responseArrivedCallback) 
    { 
     this.responseArrivedCallback = responseArrivedCallback; 
     this.requestSentEvent = new ManualResetEvent(false); 
     this.responseArrivedEvent = new ManualResetEvent(true); 
    } 

    public void MakeRequest(object requestContext, string url, BinaryDataBuffer requestPacket) 
    { 
     responseArrivedEvent.WaitOne(); 
     responseArrivedEvent.Reset(); 

     this.requestMsg = requestPacket; 
     this.requestContext = requestContext; 

     this.webRequest = WebRequest.Create(url) as HttpWebRequest; 
     this.webRequest.AllowReadStreamBuffering = true; 
     this.webRequest.ContentType = "text/plain"; 
     this.webRequest.Method = "POST"; 

     this.webRequest.BeginGetRequestStream(new AsyncCallback(this.GetRequestStreamCallback), null); 
     this.requestSentEvent.WaitOne(); 
    } 

    void GetRequestStreamCallback(IAsyncResult asynchronousResult) 
    { 
     System.IO.Stream postStream = webRequest.EndGetRequestStream(asynchronousResult); 

     postStream.Write(requestMsg.Data, 0, (int)requestMsg.Size); 
     postStream.Close(); 

     requestSentEvent.Set(); 
     webRequest.BeginGetResponse(new AsyncCallback(this.GetResponseCallback), null); 
    } 

    void GetResponseCallback(IAsyncResult asynchronousResult) 
    { 
     HttpWebResponse response = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult); 
     Stream streamResponse = response.GetResponseStream(); 
     Dim.Ensure(streamResponse.CanRead); 
     byte[] readData = new byte[streamResponse.Length]; 
     Dim.Ensure(streamResponse.Read(readData, 0, (int)streamResponse.Length) == streamResponse.Length); 
     streamResponse.Close(); 
     response.Close(); 

     webRequest = null; 
     responseArrivedEvent.Set(); 
     responseArrivedCallback(requestContext, new BinaryDataBuffer(readData)); 
    } 

    HttpWebRequest webRequest; 
    ManualResetEvent requestSentEvent; 
    BinaryDataBuffer requestMsg; 
    object requestContext; 
    ManualResetEvent responseArrivedEvent; 
    ResponseArrivedCallback responseArrivedCallback; 
} 

Utilizo este código para enviar y recibir datos a un servidor HTTP.

Actualización: después de una extensa investigación, llegué a la conclusión de que the performance problem is inherent to Silverlight v3.

+0

Por favor, muestre un código: es realmente difícil saber qué está pasando sin ver el código. –

Respuesta

4

Es muy posible que estés testigo de los efectos del algoritmo de Nagle, Proveedores:

this.webRequest.UseNagleAlgorithm.ServicePoint = false; 

Además, el Expect100Continue 'apretón de manos' es relevante para el desempeño de jabón llamada de servicio:

this.webRequest.Expect100Continue.ServicePoint = false; 

UDPATE :

Acabo de darme cuenta de que ServicePoint no está disponible en Compact Framework. Sin embargo, usted puede probar el punto haciendo:

ServicePointManager.UseNagleAlgorithm = false 

o cambiando el ajuste relavant en el archivo de configuración de aplicación, o lo que el equivalnent está en Silverlight?

+0

"no está disponible en CF": ¿qué quiere decir con CF? –

+0

Disculpa, estaba confundiendo Compact Framework con Silverlight. Así que no estoy seguro de que el objeto ServicePoint esté disponible en Silverlight antes de realizar realmente la solicitud http con GetResponse(). En CF, ese objeto se crea tarde para reducir el uso de recursos. – redcalx

+0

Aunque no puedo probarlo, probablemente tengas razón sobre la demora de Nagle. No había pensado en eso. Lamentablemente, parece que UseNagleAlgorithm no está disponible en Silverlight. De todos modos, muchas gracias por tu respuesta! Al menos ahora entiendo el problema. –

1

Sospecho que su problema es simplemente latencia. Cualquier mensaje tarda algo de tiempo en llegar al servidor, y se analiza, se procesa y se genera una respuesta, y la respuesta tarda un tiempo en volver al cliente y se analiza en una respuesta utilizable. Su rendimiento probablemente esté dominado por el tiempo de ida y vuelta.

Fundamentalmente, cualquier interfaz que cruza un límite de comunicación, ya sea entre procesos o entre máquinas, debe ser "gruesa" y no "conversadora". Envíe la mayor cantidad de información posible en cada solicitud y obtenga la mayor cantidad de datos que pueda. Puede parecer trivial en la misma máquina, pero vi una mejora diez veces mayor en el rendimiento en un servidor de aplicaciones al agrupar los comandos en un proceso de trabajo, en lugar de hacer una devolución de llamada desde el proceso de trabajo al proceso del servidor principal para cada comando.

Realmente respondió su propia pregunta indicando que obtiene un rendimiento mucho mejor cuando usa tamaños de bloque grandes.

+0

"usa tamaños de bloque grandes": Lo que no puedo entender es el factor 5000, que me parece absurdamente alto. –

1

Como Mike Dimmick mencionó en su problema de latencia de respuesta puede causar problemas, sin embargo, además de los problemas de latencia en el caso de pequeñas cargas de datos, la asignación de un hilo de ejecución (incluso con un conjunto de subprocesos) seguido por el establecimiento de la conexión representará un porcentaje mucho mayor del tiempo total empleado, que con la ruta de carga útil masiva.

Cuestiones relacionadas