2011-11-09 19 views
8

Estoy implementando un servicio asíncrono. Después de evaluar el example de Microsoft, me pregunto si su enfoque es realmente asincrónico. Estoy bastante seguro de que es así, pero algunas de las muestras que he visto en línea y el parámetro AsyncCallback hacen que me pregunte.Servicio WCF verdaderamente asíncrono

De acuerdo con el ejemplo, tenemos que poner en práctica el Begin y Fin par método como este:

public IAsyncResult BeginGetAcmeAnvil(AsyncCallback callback, object state) 
{ 
    // Starts synchronous task 
    var acmeAsyncResult = new AcmeAsyncResult<Anvil> 
    { 
    Data = new Anvil() 
    };  
    return acmeAsyncResult; 
} 

public Anvil EndGetAcmeAnvil(IAsyncResult result) 
{ 
    var acmeAsyncResult = result as AcmeAsyncResult<Anvil>; 

    return acmeAsyncResult != null 
    ? acmeAsyncResult.Data 
    : new Anvil(); 
} 

Bastante sencillo, pero ¿por qué tenemos un parámetro AsyncCallback? ¿No deberíamos hacer una llamada al callback que activará el método End?

Esto es lo que tengo en mente:

public delegate void AsyncMethodCaller(AcmeAsyncResult<Anvil> acmeAsyncResult, 
             AsyncCallback callback); 

public IAsyncResult BeginGetAcmeAnvil(AsyncCallback callback, object state) 
{ 
    var acmeAsyncResult = new AcmeAsyncResult<Anvil>(); 
    var asyncMethodCaller = new AsyncMethodCaller(GetAnvilAsync); 

    // Starts asynchronous task 
    asyncMethodCaller.BeginInvoke(acmeAsyncResult, callback, null, null); 

    return acmeAsyncResult; 
} 

private void GetAcmeAnvilAsync(AcmeAsyncResult<Anvil> acmeAsyncResult, 
           AsyncCallback callback) 
{ 
    acmeAsyncResult.Data = new Anvil(); 
    callback(acmeAsyncResult); // Triggers EndGetAcmeAnvil 
} 

public Anvil EndGetAcmeAnvil(IAsyncResult result) 
{ 
    var acmeAsyncResult = result as AcmeAsyncResult<Anvil>; 

    return acmeAsyncResult != null 
    ? acmeAsyncResult.Data 
    : new Anvil(); 
} 

Hice algunas pruebas de carga usando loadUI, pero no hubo cambios en el rendimiento obvias.

Respuesta

5

Encontré un good article explicando cómo obtener el mejor rendimiento de su servicio Async WCF.

Lo esencial es:

  1. no hacen el trabajo pesado en el Begin método y
  2. hacer que la devolución de llamada para activar el método definal.

He aquí un extracto del texto:

Para un mejor rendimiento, aquí hay dos principios al que llaman/implementar el modelo asincrónico arriba:

  • Principio 1: No realice trabajos pesados ​​dentro del método Begin ...

    El motivo es que debe devolver el hilo de llamada lo antes posible para que la persona que llama pueda programar otro trabajo. Si se trata de un hilo de UI, la aplicación necesita usar el hilo para responder a las entradas del usuario. Siempre debe poner operaciones pesadas en un hilo diferente si es posible.

  • Principio 2: evitar llamar Fin método sobre el mismo hilo de la Begin método.

    El método End normalmente está bloqueando. Espera a que la operación se complete. Si implementa el método End, verá que realmente llama a IAsyncResult.WaitHandle.WaitOne(). Por otro lado, como una implementación normal, este WaitHandle es un retraso asignado ManualResetEvent. Mientras no lo llames, no se asignará en absoluto. Para operaciones rápidas, esto es bastante barato. Sin embargo, una vez que se llama al End, debe asignarlo. El lugar correcto para llamar al End es de callback de la operación. Cuando se invoca la devolución de llamada , significa que el trabajo de bloqueo se ha completado realmente. En este punto, puede llamar al Fin para obtener datos recuperados sin sacrificar el rendimiento.

2

Creo que la razón principal por la que se separa así es que el tiempo de ejecución WCF está manejando la sincronización del hilo en lugar de tener que manejarlo manualmente.

Si invocó el método de finalización mediante la devolución de llamada, tendría que manejar la sincronización, lo que hace que el patrón sea un poco más complejo (como puede ver en sus ejemplos de codificación). El objetivo de este patrón no es que usted esté realmente al tanto de las tareas de subprocesamiento, solo quiere codificar su operación de larga ejecución sin tener que pensar en los detalles de implementación del subprocesamiento.