2012-06-02 36 views
13

Sto cercando di capire perché la prima chiamata WCF dopo l'avvio dell'applicazione client richiede molto più tempo rispetto alla seconda.Perché la prima chiamata del client WCF è lenta?

Quello che ho fatto per provare che:

  1. Implementato semplice auto ospitato WCF server e il client della console.
  2. Il server è in fase di riscaldamento - Lo eseguo e chiamo il metodo più volte prima di eseguire il test.
  3. Il collegamento è basicHttpBinding per ridurre i costi di rete e di sicurezza.
  4. Scenario di test: avviare l'app client della console, effettuando due chiamate di servizio WCF identiche in una riga.

Nei miei test vedo ~ 700 millisecondi per la prima chiamata e ~ 3 millisecondi per la seconda chiamata.

Quasi un secondo sembra essere troppo tempo per il compilatore JIT. Accetterei se quel tempo venga utilizzato per inizializzare un'infrastruttura complicata come ObjectContext in Entity Framework ma il mio codice è molto semplice e le classi proxy sono già compilate.

Ho anche provato il binding netNamedPipeBinding. Il risultato mostra un pattern - la prima chiamata dura circa 800 ms, la seconda richiede circa 8 ms.

Apprezzeranno se qualcuno può spiegare perché la prima chiamata di servizio richiede così tanto tempo.

Testato in Win 7 64 bit.

La mia implementazione è di seguito.

contratto:

[ServiceContract] 
public interface ICounter 
{ 
     [OperationContract] 
     int Add(int num); 
} 

servizio di implementazione:

public class CounterService: ICounter 
{ 
     private int _value = 0; 

     public int Add(int num) 
     { 
      _value += num; 
      Console.WriteLine("Method Add called with argument {0}. Method returned {1}", num, _value); 
      return _value; 
     } 
} 

Server Implementazione:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Uri baseAddress = new Uri("http://localhost:8080/Service"); 

     // Create the ServiceHost. 
     using (ServiceHost host = new ServiceHost(typeof(CounterService), baseAddress)) 
     { 
      host.Open(); 

      Console.WriteLine("The service is ready at {0}", baseAddress); 
      Console.WriteLine("Press <Enter> to stop the service."); 
      Console.ReadLine(); 

      // Close the ServiceHost. 
      host.Close(); 
     } 
    } 
} 

Configurazione del server:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.serviceModel> 
    <services> 
     <service name="Server.CounterService"> 
     <endpoint address="base" binding="basicHttpBinding" name="baseDefault" 
      contract="Contract.ICounter" /> 
     <endpoint address="net.pipe://localhost/Service/netNamedPipe" 
      binding="netNamedPipeBinding" name="netNamedPipeDefault" contract="Contract.ICounter" /> 
     <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name=""> 
      <serviceMetadata httpGetEnabled="true" /> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    </system.serviceModel> 
</configuration> 

implementazione client (CounterProxy viene generato dal riferimento di servizio):

Stopwatch stopWatch = new Stopwatch(); 
stopWatch.Start(); 

using (var proxy = new CounterProxy.CounterClient(_endpointConfigurationName)) 
{ 
    output = proxy.Add(1); 
} 

stopWatch.Stop(); 
// Get the elapsed time as a TimeSpan value. 
TimeSpan ts = stopWatch.Elapsed; 

funzione che contiene tale codice chiamato due volte di seguito.

configurazione client:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.serviceModel> 
    <client> 
     <endpoint address="http://localhost:8080/Service/base" binding="basicHttpBinding" 
      contract="CounterProxy.ICounter" 
      name="baseDefault" /> 
    </client> 
    </system.serviceModel> 
</configuration> 
+0

Probabilmente il caricamento/compilato l'oggetto proxy prima volta intorno, i serializzatori XML ecc Se si guarda la finestra di output dovresti vedere qualcosa come "Loaded assembly x54fjfj3fj" che è un client WCF compilato. –

+0

Incolpare i controlli di sicurezza e altre 100 incognite. C'è molto più binari coinvolti di ciò che è nel servizio distribuito. Per eseguire il debug del servizio, utilizzare i traccianti nei registri di configurazione e di visita, che mostreranno passaggi in millisecondi su che cosa si spende esattamente il tempo. Vedrai qualcosa come Autenticazione, filtri, ecc. Anche se hai qualsiasi cosa che funzioni come anonimo. –

risposta

7

Di solito la prima chiamata richiede più tempo perché in quella chiamata il numero Channel Factory viene istanziato e preparato pronto per la comunicazione e questo costa tempo.Il Channel Factory creato verrà memorizzato nella cache e riutilizzato nelle chiamate successive e quindi il tempo sarà inferiore.

http://social.msdn.microsoft.com/Forums/en/wcf/thread/43f89088-546b-46b0-adf8-214deb1741bd

+0

Ma questo suggerimento è per il lato client, se ho capito bene. non possiamo fare nulla sul lato del servizio. Non è facile dire che ogni cliente lo fa. – batmaci

+0

Sembra che Microsoft stia finalmente dando il controllo su questo: https://msdn.microsoft.com/en-us/library/hh160401%28v=vs.110%29.aspx – userx

2

ho problema simile. Quindi, cosa abbiamo effettivamente fatto, abbiamo scritto un servizio che invoca il servizio WCF per un intervallo. So che non è una soluzione elegante ma funziona.

+0

Hai qualche idea PERCHE 'sta succedendo? Sembra che molte persone lo vedano, ma nessuno che conosca ne capisce la ragione. Grazie per la risposta. –

+1

Guarda questo, ben scritto http://www.codeproject.com/Tips/114132/WCF-First-Call-Slow – GutterStink

+0

Che intervallo hai usato? Da quello che posso dire, il cache non sembra essere legato ai timeout. Ma è meno di 1 minuto. – userx

2

Se si stanno facendo le chiamate al vostro servizio WCF meno frequentemente di 15 secondi (abbiamo osservato dover attendere circa 20 secondi nella nostra applicazione), questo blog Microsoft sembra spiegare il problema: http://blogs.msdn.com/b/wenlong/archive/2010/02/11/why-does-wcf-become-slow-after-being-idle-for-15-seconds.aspx

l'articolo collega anche a questo articolo che menziona una correzione per SetMinThreads(), che sembra anche essere un problema che contribuisce: http://blogs.msdn.com/b/wenlong/archive/2010/02/11/why-are-wcf-responses-slow-and-setminthreads-does-not-work.aspx

2

stavo vedendo ritardi nella gamma di 30 secondi quando stavo creando prima il mio ser istanza proxy vice che sapevo deve essere correlata a una sorta di timeout di rete.

Alla fine per me erano in realtà i controlli per l'elenco di revoche dei certificati che venivano bloccati o frustrati dal proxy aziendale (yay Websense) come evidenziato qui: WCF service startup too slow? Have you thought to CRL check?.

per riferimento futuro e nel caso in cui il link si esaurisce è venuto giù per aggiungere quanto segue alla configurazione client:

<configuration> 
    <runtime> 
    <generatePublisherEvidence enabled=“false”/> 
    </runtime> 
</configuration> 
+2

In .NET Framework 4 e versioni successive, questo l'elemento non ha alcun effetto sui tempi di caricamento dell'assieme. Per ulteriori informazioni, vedere la sezione "Semplificazione dei criteri di sicurezza" in Modifiche di sicurezza in .NET Framework.https: //msdn.microsoft.com/en-us/library/dd233103 (v = vs.100) .aspx (passare a .NET 4.0) – Ludwo

Problemi correlati