6

Motivation

C# 5.0 async/await Konstrukte sind genial, leider aber nur Microsoft Release Candidate von sowohl .NET 4.5 und VS 2012, und gezeigt, Es wird einige Zeit dauern, bis sich diese Technologien in unseren Projekten durchsetzen werden.Asynchron-Timeout-Implementierung armen mans Asynchron mit/erwarten Konstrukte in .Net 4.0

In Stephen Toub Asynchronous methods, C# iterators, and Tasks Ich habe einen Ersatz gefunden, der in .NET 4.0 verwendet werden kann. Es gibt auch ein Dutzend anderer Implementierungen, die es möglich machen, den Ansatz auch in .NET 2.0 zu verwenden, obwohl sie wenig veraltet und weniger funktionsreich erscheinen.

Beispiel

So jetzt meine .NET 4.0 Code wie folgt aussieht (die kommentierten Abschnitte zeigen, wie es in .NET 4.5 ausgeführt wird):

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

Sieht wenig hässlich, obwohl es die Arbeit erledigt

Die Frage

Wenn ein Konstruktor, die Zeitspanne als Timeout-Parameter nimmt, so dassresultierende Verwendung CancellationTokenSource in .NET 4,5 ist,storniert innerhalb eines bestimmten Zeitraums.
. Net 4.0 ist nicht in der Lage zu Timeout, also was ist der richtige Weg, das in .NET 4.0 zu tun?

+0

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

+0

Geändert "Timer" auf "Timeout" im Titel, da die Frage über Timeout und "Timer" (für wiederkehrende mit einigen Perioden Ausführungen) war irreführend und desorientierend –

Antwort

4

Hat das wirklich etwas mit Async zu tun? Sieht so aus, als ob du nur einen Weg brauchst um den Token zu löschen, unabhängig von async/await, oder? Könnten Sie in diesem Fall einfach einen Timer erstellen, der nach dem Timeout Cancel aufruft?

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

EDIT

Meine erste Antwort oben ist die Grundidee, aber eine robustere Lösung kann in Is CancellationTokenSource.CancelAfter() leaky? (eigentlich das .Net 4.5 Implementierung des Konstrukteurs Sie suchen) zu finden. Hier ist eine Funktion, mit der Sie Timeout-Token basierend auf diesem Code erstellen können.

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

Welche Art von Timer Sie vorschlagen benutze Dax? – Lu4

+0

'System.Threading.Timer' ist, was ich dachte, aber ich würde mir vorstellen, dass jeder von ihnen funktionieren sollte - ich bin kein Experte für die Unterschiede zwischen den verschiedenen Arten von .Net' Timer's. –

+0

Aber es wird den Thread blockieren und wir werden anfangen, alle Vorteile der asynchronen Ansatz zu verlieren ... :( – Lu4

5

FWIW, Sie können async/await in 4.0-Projekten verwenden, verwenden Sie einfach the async targeting pack. Funktioniert großartig für mich!

+1

Definitiv hilfreiche Antwort – Lu4

0

Sie können immer noch CancelAfter() verwenden, die in Microsoft.Bcl.Async eine Erweiterung Methode ist, die akzeptierte Antwort oben sehr ähnlich ist.

Dies ist der refereance Souce-Code, wenn ich F12 drücken Sie die Implementierung von CancelAfter() zu sehen:

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