Kwestia ta została wysłuchana Joe Hoag na blogu Parallel Team w 2011 roku: Crafting a Task.TimeoutAfter Method.
Rozwiązanie wykorzystuje TaskCompletionSource i zawiera kilka optymalizacji (12% tylko poprzez unikanie przechwytuje), uchwyty porządki i obejmuje przypadki brzegowe jak wywołanie TimeoutAfter gdy zadanie zostało już zakończone cel, przekazując nieprawidłowe limity czasu itp
Piękno z Task.Timeout Po stwierdzeniu, że bardzo łatwo jest skomponować go z innymi kontynuacjami, ponieważ robi tylko jedną rzecz: powiadamia cię, że upłynął limit czasu. Nie próbuje "anulować twojego zadania". Możesz zdecydować, co zrobić, gdy zostanie wygenerowany wyjątek TimeoutException.
Przedstawiono również szybką implementację przy użyciu Stephen Toub przy użyciu async/await
, chociaż nie uwzględniono również przypadków krawędziowych.
Zoptymalizowany realizacja jest:
public static Task TimeoutAfter(this Task task, int millisecondsTimeout)
{
// Short-circuit #1: infinite timeout or task already completed
if (task.IsCompleted || (millisecondsTimeout == Timeout.Infinite))
{
// Either the task has already completed or timeout will never occur.
// No proxy necessary.
return task;
}
// tcs.Task will be returned as a proxy to the caller
TaskCompletionSource<VoidTypeStruct> tcs =
new TaskCompletionSource<VoidTypeStruct>();
// Short-circuit #2: zero timeout
if (millisecondsTimeout == 0)
{
// We've already timed out.
tcs.SetException(new TimeoutException());
return tcs.Task;
}
// Set up a timer to complete after the specified timeout period
Timer timer = new Timer(state =>
{
// Recover your state information
var myTcs = (TaskCompletionSource<VoidTypeStruct>)state;
// Fault our proxy with a TimeoutException
myTcs.TrySetException(new TimeoutException());
}, tcs, millisecondsTimeout, Timeout.Infinite);
// Wire up the logic for what happens when source task completes
task.ContinueWith((antecedent, state) =>
{
// Recover our state data
var tuple =
(Tuple<Timer, TaskCompletionSource<VoidTypeStruct>>)state;
// Cancel the Timer
tuple.Item1.Dispose();
// Marshal results to proxy
MarshalTaskResults(antecedent, tuple.Item2);
},
Tuple.Create(timer, tcs),
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
return tcs.Task;
}
i realizacja Stephena Toub za, bez kontroli przypadków brzegowych:
public static async Task TimeoutAfter(this Task task, int millisecondsTimeout)
{
if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout)))
await task;
else
throw new TimeoutException();
}
jestem zdezorientowany, pytasz o 'async'-'await', która to nowa funkcja C# 5.0, ale twoje pytanie jest oznaczone jako C# 4.0. Więc kto to jest? – svick
przełączane znaczniki, aby dopasować pytanie – Alex
@ElHaix Inni wydają się sugerować, nie rzucając wyjątku.To jest normalne, aby rzucić wyjątek, ponieważ kod będzie bardziej elegancki, obsługiwany i jest dobrym sposobem na wdrożenie *** [Zadanie Anulowanie Pattern] (http://msdn.microsoft.com/en-us/library/dd997396.aspx) *** - "użyj metody ThrowIfCancellationRequested. Zadanie anulowane w ten sposób przechodzi w stan Cancelled, czyli wywołanie kod może posłużyć do sprawdzenia, czy zadanie odpowiedziało na jego żądanie anulowania. " Wyobraź sobie, że masz wiele metod, używając tego samego tokena anulowania. Użyj wyjątku, aby uprościć całą logikę. –