Sto cercando un modo efficiente per generare un'eccezione di timeout se un metodo sincrono richiede troppo tempo per essere eseguito. Ho visto alcuni campioni ma niente che faccia esattamente quello che voglio.Monitoraggio di un metodo sincrono per timeout
Che cosa devo fare è
- Verificare che il metodo di sincronizzazione non superare il suo SLA
- Se non un'eccezione timeout
faccio non devono terminare il metodo di sincronizzazione se viene eseguito troppo a lungo. (Più guasti causano l'intervento di un interruttore automatico e impediscono il guasto a cascata)
La mia soluzione è mostrata di seguito. Si noti che io passo un metodo di sincronizzazione al metodo di sincronizzazione nella speranza che risparmi una richiesta di cancellazione al timeout. Anche la mia soluzione restituisce un'attività che può quindi essere attesa in ecc. Come desiderato dal mio codice di chiamata.
La mia preoccupazione è che questo codice crei due compiti per metodo monitorato. Penso che il TPL gestirà bene, ma vorrei confermarlo.
Ha senso? C'è un modo migliore per farlo?
private Task TimeoutSyncMethod(Action<CancellationToken> syncAction, TimeSpan timeout)
{
var cts = new CancellationTokenSource();
var outer = Task.Run(() =>
{
try
{
//Start the synchronous method - passing it a cancellation token
var inner = Task.Run(() => syncAction(cts.Token), cts.Token);
if(!inner.Wait(timeout))
{
//Try give the sync method a chance to abort grecefully
cts.Cancel();
//There was a timeout regardless of what the sync method does - so throw
throw new TimeoutException("Timeout waiting for method after " + timeout);
}
}
finally
{
cts.Dispose();
}
}, cts.Token);
return outer;
}
Edit:
Utilizzando @ risposta di Timothy ora sto usando questo. Anche se non molto meno codice, è molto più chiaro. Grazie!
private Task TimeoutSyncMethod(Action<CancellationToken> syncAction, TimeSpan timeout)
{
var cts = new CancellationTokenSource();
var inner = Task.Run(() => syncAction(cts.Token), cts.Token);
var delay = Task.Delay(timeout, cts.Token);
var timeoutTask = Task.WhenAny(inner, delay).ContinueWith(t =>
{
try
{
if(!inner.IsCompleted)
{
cts.Cancel();
throw new TimeoutException("Timeout waiting for method after " + timeout);
}
}
finally
{
cts.Dispose();
}
}, cts.Token);
return timeoutTask;
}
State usando .NET 4.5 e asincrone/aspettano? –
http://stackoverflow.com/questions/299198/implement-c-sharp-generic-timeout –
Robert: Grazie, la mia preoccupazione è il Thread.Abort(). Io non lo faccio. Sembra troppo drastico. Nel mio caso non ho bisogno di abortire. – Andre