2012-06-02 32 views
13

Estoy tratando de averiguar por qué la primera llamada WCF después del inicio de la aplicación cliente toma mucho más tiempo en comparación con la segunda.¿Por qué es lenta la primera llamada de cliente WCF?

Lo que hice para probar que:

  1. Implementado simple auto organizadas WCF servidor y el cliente de consola.
  2. El servidor se calienta - Lo ejecuto y llamo al método varias veces antes de ejecutar la prueba.
  3. El enlace es basicHttpBinding para reducir los gastos generales de seguridad y de red.
  4. Escenario de prueba: inicie la aplicación del cliente de la consola, haciendo dos llamadas al servicio WCF idénticas en una fila.

En mis pruebas veo ~ 700 milisegundos para la primera llamada y ~ 3 milisegundos para la segunda llamada.

Casi un segundo parece ser demasiado tiempo para el compilador JIT. Lo aceptaría si ese tiempo se usa para inicializar alguna infraestructura complicada como ObjectContext en Entity Framework, pero mi código es muy simple y las clases de proxy ya están compiladas.

También intenté netNamedPipeBinding encuadernación. El resultado prueba el patrón: la primera llamada tarda ~ 800 ms, la segunda llamada demora ~ 8 ms.

Agradeceré si alguien puede explicar por qué la primera llamada de servicio lleva tanto tiempo.

Probado en Win 7 64 bit.

Mi implementación está por debajo.

Contrato:

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

implementación del servicio:

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

Servidor de Aplicación:

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

Configuración del servidor:

<?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> 

implementación del cliente (CounterProxy se genera a partir referencia de servicio):

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; 

función que contenga ese código se llama dos veces en una fila.

de configuración del cliente:

<?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

Probablemente cargar/compilado el objeto proxy primera vez, los serializadores XML, etc Si usted mira la ventana de salida, deberías ver algo como "Loaded assembly x54fjfj3fj", que es un cliente compilado de WCF. –

+0

Culpo a las comprobaciones de seguridad y otras 100 incógnitas. Hay mucho más binarios involucrados que lo que está en servicio desplegado. Para depurar los rastreadores de uso del servicio en los registros de configuración y visita, mostrarán los pasos en milisegundos en los que se gasta exactamente el tiempo. Verá algo así como Autenticación, filtros, etc. incluso si tiene todo actuando como anónimo. –

Respuesta

7

Por lo general, la primera llamada lleva más tiempo porque en esa llamada el Channel Factory se crea una instancia y se prepara para la comunicación y eso cuesta tiempo.El Channel Factory creado se almacenará en caché y se reutilizará en llamadas posteriores, por lo que el tiempo será menor.

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

+0

Pero esta sugerencia es para el lado del cliente, si entiendo correctamente. no podemos hacer nada por el lado del servicio. No es fácil decir que cada cliente haga eso. – batmaci

+0

Parece que Microsoft finalmente le da cierto control sobre esto: https://msdn.microsoft.com/en-us/library/hh160401%28v=vs.110%29.aspx – userx

2

tengo problema similar. Entonces, lo que realmente hicimos, escribimos un servicio que invoca el servicio WCF por algún intervalo. Sé que no es una solución elegante, pero está funcionando.

+0

¿Tiene alguna idea de por qué está sucediendo? Parece que mucha gente lo ve, pero nadie que yo conozca entiende el motivo. Gracias por responder. –

+1

Mire esto, bien escrito http://www.codeproject.com/Tips/114132/WCF-First-Call-Slow – GutterStink

+0

¿Qué intervalo usó? Por lo que puedo decir, la memoria caché no parece estar vinculada a los tiempos de espera. Pero es menos de 1 minuto. – userx

2

Si va a realizar llamadas a su servicio WCF con menos frecuencia de 15 segundos (se observó el tener que esperar unos 20 segundos en nuestra aplicación), este blog Microsoft parece explicar su problema: http://blogs.msdn.com/b/wenlong/archive/2010/02/11/why-does-wcf-become-slow-after-being-idle-for-15-seconds.aspx

el artículo también se une a esta entrada que menciona una solución para SetMinThreads(), que también parece ser un problema que contribuye: http://blogs.msdn.com/b/wenlong/archive/2010/02/11/why-are-wcf-responses-slow-and-setminthreads-does-not-work.aspx

2

que estaba viendo retrasos en el rango de 30 segundos cuando se estaba creando mi primera ser instancia de proxy vice que sabía que debe estar relacionada con algún tipo de tiempo de espera de red.

Al final para mí fue en realidad los controles para la lista de revocación de certificados que estaban siendo bloqueados o frustrados por el proxy corporativo (yay Websense) como se destaca aquí: WCF service startup too slow? Have you thought to CRL check?.

Para referencia futura y en caso de que el enlace se agota todo se redujo a añadir lo siguiente a la configuración del cliente:

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

En .NET Framework 4 y versiones posteriores, este el elemento no tiene efecto en los tiempos de carga del ensamblaje. Para obtener más información, consulte la sección "Simplificación de la política de seguridad" en Cambios de seguridad en .NET Framework.https: //msdn.microsoft.com/en-us/library/dd233103 (v = vs.100) .aspx (cambie a .NET 4.0) – Ludwo

Cuestiones relacionadas