Я ищу эффективный способ выбросить исключение тайм-аута, если синхронный метод занимает слишком много времени для выполнения. Я видел несколько образцов, но ничего, что делает то, что я хочу.Мониторинг синхронного метода для тайм-аута
Что мне нужно сделать, это
- Убедитесь, что синхронизация метод не превышает его ОАС
- Если это бросить исключение тайм-аут
я не должны прекратить действие sync, если он выполняется слишком долго. (Несколько отказов отключат автоматический выключатель и предотвратит каскадный отказ)
Мое решение пока показано ниже. Обратите внимание, что я передаю метод CancellationToken методу синхронизации в надежде, что он выполнит запрос на отмену таймаута. Также мое решение возвращает задачу, которую можно затем ожидать по иному по моему коду вызова.
Я обеспокоен тем, что этот код создает две задачи для каждого проверяемого метода. Я думаю, что TPL справится с этим хорошо, но я хотел бы подтвердить.
Имеет ли это смысл? Есть лучший способ сделать это?
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:
Используя @ ответ Тимофея сейчас я использую это. Хотя не намного меньше кода, это намного яснее. Благодаря!
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;
}
Вы используете .NET 4.5 и асинхронной/Await? –
http://stackoverflow.com/questions/299198/implement-c-sharp-generic-timeout –
Robert: Спасибо, моя забота о том, что есть Thread.Abort(). Я этого не делаю. Кажется, слишком резкий. В моем случае мне не нужно прерывать. – Andre