Szukam skutecznego sposobu na wyrzucenie wyjątku limitu czasu, jeśli wykonanie metody synchronicznej trwa zbyt długo. Widziałem kilka próbek, ale nic, co całkiem robi to, co chcę.Monitorowanie synchronicznej metody limitu czasu
Co muszę zrobić, to
- Sprawdź, czy metoda synchronizacji nie przekracza jego SLA
- Jeśli tak rzucać wyjątek Timeout
zrobić nie trzeba rozwiązać metoda synchronizacji, jeśli jest wykonywana zbyt długo. (Wielokrotne awarie wyzwolą wyłącznik i zapobiegną awariom kaskadowania)
Moje dotychczasowe rozwiązanie jest pokazane poniżej. Zwróć uwagę, że przekazuję Token Anulowania do metody synchronizacji w nadziei, że będzie honorować żądanie anulowania po upływie limitu czasu. Również moje rozwiązanie zwraca zadanie, które można następnie oczekiwać na itp. Zgodnie z życzeniem mojego kodu wywołującego.
Obawiam się, że ten kod tworzy dwa zadania na monitorowaną metodę. Myślę, że TPL sobie z tym poradzi, ale chciałbym to potwierdzić.
Czy to ma sens? Czy jest lepszy sposób to zrobić?
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:
Korzystanie @ odpowiedź Timothy'ego Obecnie używam tego. O ile nie jest to znacznie mniejszy kod, jest on o wiele jaśniejszy. Dzięki!
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;
}
Czy używasz .NET 4.5 i asynchroniczny/Oczekujcie? –
http://stackoverflow.com/questions/299198/implement-c-sharp-generic-timeout –
Robert: Dzięki, moja troska jest Thread.Abort(). Nie chcę tego robić. Wydaje się zbyt drastyczny. W moim przypadku nie muszę przerwać. – Andre