6

Motywacja

C# 5.0 asynchroniczny/czekają konstrukty są niesamowite, niestety jeszcze Microsoft pokazano tylko kandydata uwalniania zarówno .NET 4.5 i VS 2012, i to zajmie trochę czasu, zanim technologie te zostaną szeroko przyjęte w naszych projektach.Wdrażanie limit czasu transmisji asynchronicznej z wykorzystaniem słabe mans asynchronicznie/czekają konstrukty w .NET 4.0

W Stephen Toub's Asynchronous methods, C# iterators, and Tasks Znalazłem zamiennik, który może być ładnie używany w .NET 4.0. Istnieje również kilkanaście innych implementacji, które umożliwiają korzystanie z tego podejścia nawet w .NET 2.0, chociaż wydają się one nieco przestarzałe i mniej bogate w funkcje.

Przykład

Więc teraz mój kod .NET 4.0 wygląda (komentowanym sekcje pokazać jak to się robi w .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)); 
    } 
} 

Wygląda trochę brzydki choć spełnia swoje zadanie

Pytanie

Podczas korzystania z CancellationTokenSource w .NET 4.5 istnieje konstruktor, który przyjmuje czas jako parametr limitu czasu, dzięki czemu wyniknie CancellationTokenSource anuluje w określonym czasie.
.Net 4.0 nie może przekroczyć limitu czasu, więc jaki jest prawidłowy sposób to zrobić w .Net 4.0?

+0

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

+0

Zmieniono "timer" na "timeout" w tytule, ponieważ pytanie dotyczy limitu czasu i "timera" (używanego do powtarzania z niektórymi okresowymi egzekucjami) było mylące i dezorientujące. –

Odpowiedz

4

Czy to naprawdę ma coś wspólnego z async/oczekiwaniem? Wygląda na to, że potrzebujesz tylko sposobu na anulowanie tokena, niezależnie od asynchronizacji/oczekiwania, prawda? W takim przypadku, czy mógłbyś po prostu utworzyć zegar, który wywołuje Anuluj po upływie czasu oczekiwania? powyżej

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

EDIT

Moja początkowa reakcja jest podstawowa idea, ale bardziej wytrzymałe rozwiązanie można znaleźć w Is CancellationTokenSource.CancelAfter() leaky? (właściwie realizację konstruktora jesteś stara .Net 4.5). Oto funkcja, której możesz użyć do tworzenia tokenów limitu czasu na podstawie tego kodu.

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

Jakiego rodzaju timera proponuje się używać Dax? – Lu4

+0

'System.Threading.Timer' jest tym, o czym myślałem, ale wyobrażam sobie, że któryś z nich powinien działać - nie jestem ekspertem od różnic między różnymi rodzajami .Net' Timer's. –

+0

Ale to zablokuje wątek, a zaczniemy tracić wszystkie zalety asynchronicznego podejścia ... :( – Lu4

5

FWIW, możesz używać async/await w 4.0 projektach, wystarczy użyć the async targeting pack. Działa świetnie dla mnie!

+1

Zdecydowanie pomocna odpowiedź – Lu4

0

Można nadal używać CancelAfter(), który jest metoda rozszerzenie Microsoft.Bcl.Async która jest bardzo podobna do zaakceptowanej odpowiedzi powyżej.

Jest to kod refereance sos po naciśnięciu klawisza F12, aby zobaczyć realizację 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); 
    }