2015-01-03 2 views
1

У меня есть следующее расширение, которое позволяет мне заставить тайм-аут выполнять задачу.Расписание задач при вызове внешнего метода

public static async Task<T> TimeoutAfter<T>(this Task<T> task, TimeSpan timeSpan, string message = null) 
{ 
    if (task == await Task.WhenAny(task, Task.Delay(timeSpan))) 
     return await task; 
    else 
    { 
     throw new TimeoutException(message); 
    } 
} 

У меня есть следующая задача:

private async Task<string> TestTask(PageData page) 
{ 
    await Task.Delay(TimeSpan.FromSeconds(10)); 
    return "teststring"; 
} 

Когда я называю задачу, используя следующий я получаю желаемый результат.

var teststring = await TestTask() 
       .TimeoutAfter(TimeSpan.FromSeconds(5), "timeout message"); 

я выдаю я имею что когда я вызываю метод во внешней библиотеке (в данном случае с ++ CLR библиотеки классов), код внутри TimeoutAfter() никогда не будет достигнуто, и задача никогда не таймаута. Я могу исправить проблему, используя Task.Factory.StartNew() (см. Ниже), передав обратный вызов долговременной задаче и создав задачу Task.Delay перед запуском основной задачи, но это не будет работать как расширение ,

private async Task<T> Timeout<T>(Func<Task<T>> taskFunc) 
{ 
    var taskWait = Task.Delay(TimeSpan.FromSeconds(15)); 
    var task = Task.Factory.StartNew(() => taskFunc()); 

    if (task == await Task.WhenAny(task, taskWait)) 
     return await (await task); 
    else 
    { 
     throw new TimeoutException("timeout"); 
    } 
} 

Почему кажется, что код в TimeoutAfter() только выполнение, когда определенное содержание в задаче она простирающаяся? Какую функциональность можно добавить к расширению, чтобы это не происходило?

+1

Вы делаете это в Windows Forms или WPF UI, случайно? Можете ли вы создать короткую, но полную программу, демонстрирующую проблему? Это не помогает, что мы ничего не знаем о методе, который вы вызываете, асинхронно? # –

+1

Вы должны знать, что это не «тайм-аут» в традиционном смысле. Ваша задача не прервана, только время ожидания. Задача будет продолжаться, и если это бесконечный цикл или какая-то другая долго работающая задача, у нее могут быть очень странные побочные эффекты. Вероятно, вы также не будете знать, будут ли исключения выбраны в этой задаче после таймаута. –

+0

@JonSkeet Выполняется код в консольном приложении, метод, вызываемый в задаче, вызывает метод в библиотеке классов CLR CLR, который, в свою очередь, вызывает внешние DLL, связанные с библиотекой изображений. Существуют ли определенные условия, при которых задача будет выполняться синхронно, а расширение не будет вызвано? – jimmyjambles

ответ

-2

Я думаю, что ваша главная проблема заключается в том, что вы просто не запускаете свою задачу, когда пытаетесь использовать метод расширения.

A Task полностью асинхронный и must be started для достижения своего кода. Одним из способов запуска задачи является использование StartNew, как вы пробовали на заводе.

Но вы также можете просто позвонить по методу Start. Единственное, что вам нужно предупредить, это то, что если запуск уже запущен или уже завершен, вы получите исключение при вызове Start.

Так что, я думаю, ваше решение может быть:

public static async Task<T> TimeoutAfter<T>(this Task<T> task, TimeSpan timeSpan, string message = null) 
{ 
    if(task.Status != TaskStatus.Running && task.Status != TaskStatus.RanToCompletion){ 
     task.Start(); 
    } 
    if (task == await Task.WhenAny(task, Task.Delay(timeSpan))) 
     return await task; 
    else 
    { 
     throw new TimeoutException(message); 
    } 
} 
+0

Вам не нужно явно запускать задачу 'async' с помощью' Start' – i3arnon

+0

После того, как вы держите ссылку на задание, она уже запущена, проблема, с которой я сталкиваюсь, заключается в том, что никакой код в расширении не вызван с определенными базовыми задачами – jimmyjambles

Смежные вопросы