Ich bin auf der Suche nach einer effizienten Möglichkeit, eine Timeout-Ausnahme zu werfen, wenn eine synchrone Methode zu lange dauert. Ich habe einige Samples gesehen, aber nichts, was ich will.Überwachung einer synchronen Methode für Timeout
Was ich tun müssen, ist
- Überprüfen Sie, ob die Synchronisierungsmethode hat seine SLA überschreiten
- Wenn es ein Timeout Ausnahme
ich nicht müssen das beenden wirft Sync-Methode, wenn es zu lange ausgeführt wird. (Mehrere Fehler lösen einen Leistungsschalter aus und verhindern einen Kaskadenfehler)
Meine bisherige Lösung ist unten aufgeführt. Beachten Sie, dass ich ein CancellationToken an die Synchronisierungsmethode weitergebe, in der Hoffnung, dass eine Abbruchanforderung bei Timeout berücksichtigt wird. Auch meine Lösung gibt eine Aufgabe zurück, auf die dann wie von meinem Anrufcode gewünscht gewartet werden kann.
Meine Sorge ist, dass dieser Code erstellt zwei Aufgaben pro Methode Überwachung. Ich denke, die TPL wird das gut hinkriegen, aber ich würde es gerne bestätigen.
Macht das Sinn? Gibt es einen besseren Weg, dies zu tun?
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:
@ Antwort des Timothy verwendet nun diese mit mir. Während nicht wesentlich weniger Code ist es viel klarer. Vielen Dank!
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;
}
Sind Sie .NET 4.5 und Asynchron/await mit:
Mehr hier zu finden? –
http://stackoverflow.com/questions/299198/implement-c-sharp-generic-timeout –
Robert: Danke, meine Sorge dort ist der Thread.Abort(). Ich mache das nicht. Scheint zu drastisch. In meinem Fall muss ich nicht abbrechen. – Andre