6

motivación

C# 5.0 asíncrono/aguardan construcciones son impresionantes, sin embargo, por desgracia Microsoft sólo muestran una versión candidata de ambos .NET 4.5 y VS 2012, y se tomará algún tiempo hasta que estas tecnologías sean ampliamente adoptadas en nuestros proyectos.La implementación de tiempo de espera asincrónico utilizando pobres asíncrono Mans/esperan construcciones en .Net 4.0

En Stephen Toub's Asynchronous methods, C# iterators, and Tasks He encontrado un reemplazo que se puede utilizar muy bien en .NET 4.0. También hay una docena de otras implementaciones que hacen posible el uso del enfoque incluso en .NET 2.0, aunque parecen poco anticuadas y menos ricas en funciones.

Ejemplo

Así que ahora mi código .NET 4.0 se parece a (las secciones comentadas muestran cómo se hace en .NET 4.5):

//private async Task ProcessMessageAsync() 
private IEnumerable<Task> ProcessMessageAsync() 
{ 
    //var udpReceiveResult = await udpClient.ReceiveAsync(); 

    var task = Task<UdpAsyncReceiveResult> 
       .Factory 
       .FromAsync(udpClient.BeginReceive, udpClient.EndReceive, null); 

    yield return task; 

    var udpReceiveResult = task.Result; 

    //... blah blah blah 

    if (message is BootstrapRequest) 
    { 
     var typedMessage = ((BootstrapRequest)(message)); 

     // !!! .NET 4.0 has no overload for CancellationTokenSource that 
     // !!! takes timeout parameter :(
     var cts 
      = new CancellationTokenSource(BootstrapResponseTimeout); // Error here 

     //... blah blah blah 

     // Say(messageIPEndPoint, responseMessage, cts.Token); 

     Task.Factory.Iterate(Say(messageIPEndPoint, responseMessage, cts.Token)); 
    } 
} 

Parece poco fea pesar de que hace el trabajo

La pregunta

Al utilizar CancellationTokenSource en .NET 4.5 hay un constructor que toma intervalo de tiempo como un parámetro de tiempo de espera, de modo que resultante CancellationTokenSource cancela dentro de un período de tiempo especificado.
.Net 4.0 no puede esperar, ¿cuál es la forma correcta de hacerlo en .Net 4.0?

+0

pregunta relacionada: http://stackoverflow.com/questions/9110472/using-async-await-on- net-4 – CodesInChaos

+0

Cambió "temporizador" a "tiempo de espera" en el título ya que la pregunta es sobre tiempo de espera y "temporizador" (usado para recurrir con algunas ejecuciones de período) fue engañoso y desorientador –

Respuesta

4

¿Esto realmente tiene algo que ver con async/await? Parece que solo necesitas una forma de cancelar el token, independientemente de async/await, ¿no? En ese caso, ¿podría simplemente crear un temporizador que llame a Cancelar después del tiempo de espera?

new Timer(state => cts.Cancel(), null, BootstrapResponseTimeout, Timeout.Infinite); 

EDITAR

Mi respuesta inicial de arriba es la idea básica, pero una solución más robusta se puede encontrar en la Is CancellationTokenSource.CancelAfter() leaky? (en realidad, la aplicación .Net 4.5 del constructor que está buscando). Aquí hay una función que puede usar para crear tokens de tiempo de espera basados ​​en ese código.

public static CancellationTokenSource CreateTimeoutToken(int dueTime) { 
    if (dueTime < -1) { 
     throw new ArgumentOutOfRangeException("dueTime"); 
    } 
    var source = new CancellationTokenSource(); 
    var timer = new Timer(self => { 
     ((Timer)self).Dispose(); 
     try { 
      source.Cancel(); 
     } catch (ObjectDisposedException) {} 
    }); 
    timer.Change(dueTime, -1); 
    return source; 
} 
+0

¿Qué tipo de temporizador le propone usar Dax? – Lu4

+0

'System.Threading.Timer' es lo que estaba pensando, pero me imagino que cualquiera de ellos debería funcionar, no soy un experto en las diferencias entre los distintos tipos de .Net' Timer's. –

+0

Pero bloqueará el hilo y comenzaremos a perder todos los beneficios del enfoque asincrónico ... :( – Lu4

5

FWIW, puede usar async/await en proyectos de 4.0, solo use the async targeting pack. ¡Funciona genial para mí!

+1

Respuesta definitivamente útil – Lu4

0

Puede seguir utilizando CancelAfter(), que es un método de extensión en Microsoft.Bcl.Async que es muy similar a la respuesta aceptada anteriormente.

Este es el código refereance Souce al pulsar F12 para ver la implementación de CancelAfter():

/// <summary>Cancels the <see cref="T:System.Threading.CancellationTokenSource" /> after the specified duration.</summary> 
    /// <param name="source">The CancellationTokenSource.</param> 
    /// <param name="dueTime">The due time in milliseconds for the source to be canceled.</param> 
    public static void CancelAfter(this CancellationTokenSource source, int dueTime) 
    { 
    if (source == null) 
     throw new NullReferenceException(); 
    if (dueTime < -1) 
     throw new ArgumentOutOfRangeException("dueTime"); 
    Contract.EndContractBlock(); 
    Timer timer = (Timer) null; 
    timer = new Timer((TimerCallback) (state => 
    { 
     timer.Dispose(); 
     TimerManager.Remove(timer); 
     try 
     { 
     source.Cancel(); 
     } 
     catch (ObjectDisposedException ex) 
     { 
     } 
    }), (object) null, -1, -1); 
    TimerManager.Add(timer); 
    timer.Change(dueTime, -1); 
    } 
Cuestiones relacionadas