Qui è un esempio completamente lavorato basa sulla sommità votato risposta, che è:
int timeout = 1000;
var task = SomeOperationAsync();
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
} else {
// timeout logic
}
Il vantaggio principale della realizzazione in questa risposta è che sono stati aggiunti generici, per cui la funzione (o attività) può restituire un valore. Ciò significa che ogni funzione esistente può essere avvolto in una funzione di timeout, es .:
Prima:
int x = MyFunc();
Dopo:
// Throws a TimeoutException if MyFunc takes more than 1 second
int x = TimeoutAfter(MyFunc, TimeSpan.FromSeconds(1));
Questo codice richiede NET 4.5.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TaskTimeout
{
public static class Program
{
/// <summary>
/// Demo of how to wrap any function in a timeout.
/// </summary>
private static void Main(string[] args)
{
// Version without timeout.
int a = MyFunc();
Console.Write("Result: {0}\n", a);
// Version with timeout.
int b = TimeoutAfter(() => { return MyFunc(); },TimeSpan.FromSeconds(1));
Console.Write("Result: {0}\n", b);
// Version with timeout (short version that uses method groups).
int c = TimeoutAfter(MyFunc, TimeSpan.FromSeconds(1));
Console.Write("Result: {0}\n", c);
// Version that lets you see what happens when a timeout occurs.
try
{
int d = TimeoutAfter(
() =>
{
Thread.Sleep(TimeSpan.FromSeconds(123));
return 42;
},
TimeSpan.FromSeconds(1));
Console.Write("Result: {0}\n", d);
}
catch (TimeoutException e)
{
Console.Write("Exception: {0}\n", e.Message);
}
// Version that works on tasks.
var task = Task.Run(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(1));
return 42;
});
// To use async/await, add "await" and remove "GetAwaiter().GetResult()".
var result = task.TimeoutAfterAsync(TimeSpan.FromSeconds(2)).
GetAwaiter().GetResult();
Console.Write("Result: {0}\n", result);
Console.Write("[any key to exit]");
Console.ReadKey();
}
public static int MyFunc()
{
return 42;
}
public static TResult TimeoutAfter<TResult>(
this Func<TResult> func, TimeSpan timeout)
{
var task = Task.Run(func);
return TimeoutAfterAsync(task, timeout).GetAwaiter().GetResult();
}
private static async Task<TResult> TimeoutAfterAsync<TResult>(
this Task<TResult> task, TimeSpan timeout)
{
var result = await Task.WhenAny(task, Task.Delay(timeout));
if (result == task)
{
// Task completed within timeout.
return task.GetAwaiter().GetResult();
}
else
{
// Task timed out.
throw new TimeoutException();
}
}
}
}
Avvertenze
Dopo aver dato questa risposta, il suo genere non una buona pratica per avere le eccezioni sollevate nel codice durante il normale funzionamento, a meno che non dovete assolutamente:
- Ogni volta che viene lanciata un'eccezione, è un'operazione estremamente pesante,
- Le eccezioni possono rallentare il codice di un fattore pari o superiore a 100 se le eccezioni sono in un anello chiuso.
Utilizzare questo codice solo se non è assolutamente possibile modificare la funzione che si sta chiamando in modo che scada dopo uno specifico TimeSpan
.
Questa risposta è realmente applicabile solo quando si tratta di librerie di librerie di terze parti che non è possibile refactoring includere un parametro di timeout.
come scrivere codice robusto
Se si desidera scrivere codice robusto, la regola generale è questa:
Ogni singola operazione che potrebbe potenzialmente bloccare a tempo indeterminato, deve avere un timeout.
Se non si rispettare tale regola, il codice finirà per colpire un'operazione che non riesce per qualche motivo, allora sarà bloccare a tempo indeterminato, e la vostra applicazione ha appena appeso in modo permanente.
Se c'è stato un timeout ragionevole dopo un po 'di tempo, la tua app si bloccherebbe per un periodo di tempo molto lungo (ad esempio 30 secondi), quindi visualizzerebbe un errore e continuerà sulla sua strada allegra, o riproverà.
Hai ragione. Sono sorpreso che non preveda un timeout. Forse in .NET 5.0 ... Ovviamente possiamo costruire il timeout nel compito stesso, ma non va bene, queste cose devono venire gratis. – Aliostad
Anche se richiederebbe una logica per il timeout a due livelli che si descrive, .NET 4.5 offre in effetti un metodo semplice per la creazione di un '' CancellationTokenSource' basato sul timeout (http://msdn.microsoft.com/en-us /library/system.threading.cancellationtokensource(v=VS.110).aspx). Sono disponibili due overload per il costruttore, uno con un ritardo di un millisecondo e uno con un ritardo di TimeSpan. – patridge
Qui la completa fonte di lib libra: http://stackoverflow.com/questions/11831844/unobservedtaskexception-being-throw-but-it-is-handled-by-a-taskscheduler-unobser –