2010-03-08 10 views
5

Quando invio/ricezione di dati tramite HttpWebRequest (su Silverlight) in piccoli blocchi, misuro il molto piccola portata di 500 byte/s per un "localhost" connessione. Quando si inviano i dati in blocchi grandi, ottengo 2 MB/s, ovvero 5000 volte più veloce.Che cosa potrebbe causare il grande sovraccarico di effettuare una chiamata HttpWebRequest?

Qualcuno sa cosa potrebbe causare questo sovraccarico incredibilmente grande?

Ulteriori informazioni:

  • sto usando il metodo HTTP POST
  • ho fatto la misurazione delle prestazioni sia su Firefox 3.6 e Internet Explorer 7. Entrambi hanno mostrato risultati simili.
  • mio CPU è caricato solo il 10% (quad-core, quindi il 40% in realtà)
  • WebClient ha mostrato risultati simili
  • WCF/SOAP showed similar results

Aggiornamento: il codice di Silverlight lato client che uso è essenzialmente la mia implementazione della classe WebClient. Il motivo per cui l'ho scritto è perché ho notato lo stesso problema di prestazioni con WebClient e ho pensato che HttpWebRequest avrebbe consentito di modificare il problema delle prestazioni. Purtroppo, questo non ha funzionato. L'implementazione è la seguente:

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; 
} 

Io uso questo codice per inviare dati avanti e indietro su un server HTTP.

Aggiornamento: dopo approfondite ricerche, concludo che the performance problem is inherent to Silverlight v3.

+0

Si prega di mostrare un po 'di codice - è davvero difficile dire cosa sta succedendo senza vedere il codice. –

risposta

4

Molto probabilmente il gioco è assistendo gli effetti del l'algoritmo Nagle, provare:

this.webRequest.UseNagleAlgorithm.ServicePoint = false; 

Inoltre, l'Expect100Continue 'stretta di mano' è rilevante per il sapone prestazioni chiamata di servizio:

this.webRequest.Expect100Continue.ServicePoint = false; 

UDPATE :

Appena realizzato che ServicePoint non è disponibile in Compact Framework. Tuttavia è possibile dimostrare il punto facendo:

ServicePointManager.UseNagleAlgorithm = false 

o modifica l'impostazione relavant nel file di configurazione dell'applicazione, o qualunque sia l'equivalnent è in Silverlight?

+0

"non è disponibile in CF": cosa intendi per CF? –

+0

Mi spiace, stavo ottenendo il Compact Framework confuso con Silverlight. Quindi non sono sicuro che ServicePoint sia l'oggetto disponibile in silverlight prima di effettuare effettivamente la richiesta http con GetResponse(). In CF quell'oggetto viene creato in ritardo per ridurre l'utilizzo delle risorse. – redcalx

+0

Anche se non riesco a testarlo, probabilmente hai ragione riguardo al ritardo Nagle. Non ci avevo pensato. Purtroppo, UseNagleAlgorithm non è disponibile in Silverlight. Comunque, grazie mille per la tua risposta! Almeno ora capisco il problema. –

1

Sospetto che il tuo problema sia semplicemente la latenza. Qualsiasi messaggio impiega del tempo per arrivare al server, e viene analizzato ed elaborato e viene generata una risposta, e la risposta richiede del tempo per tornare al client e viene analizzata in una risposta utilizzabile. Molto probabilmente il tuo rendimento è dominato dal tempo di andata e ritorno.

Fondamentalmente qualsiasi interfaccia che attraversa un confine di comunicazione - sia esso inter-processo o inter-macchina - dovrebbe essere "grosso" e non "chiacchierone". Invia quante più informazioni possibili in ogni richiesta e ottieni più dati in risposta che puoi. Può sembrare banale sulla stessa macchina, ma ho visto un miglioramento decuplicato delle prestazioni in un server delle applicazioni raggruppando i comandi in un processo di lavoro, anziché effettuare una richiamata dal processo di lavoro nel processo del server principale per ciascun comando.

Hai davvero risposto alla tua domanda indicando che ottieni prestazioni molto migliori quando usi blocchi di grandi dimensioni.

+0

"use large block size": Quello che non riesco a capire è il fattore 5000, che mi sembra assurdamente alto. –

1

Come ha menzionato Mike Dimmick nella sua risposta, il problema di latenza può causare problemi, tuttavia oltre ai problemi di latenza nel caso di payload di dati molto piccoli, l'allocazione di un thread per l'esecuzione (anche con un threadpool) seguita dalla creazione di la connessione rappresenterà una percentuale molto maggiore del tempo totale impiegato, rispetto alla rotta del carico utile alla rinfusa.

Problemi correlati