2014-11-07 5 views
26

В C# У меня есть следующие два простых примера:.ждут Task.Delay() против Task.Delay() Wait()

[Test] 
public void TestWait() 
{ 
    var t = Task.Factory.StartNew(() => 
    { 
     Console.WriteLine("Start"); 
     Task.Delay(5000).Wait(); 
     Console.WriteLine("Done"); 
    }); 
    t.Wait(); 
    Console.WriteLine("All done"); 
} 

[Test] 
public void TestAwait() 
{ 
    var t = Task.Factory.StartNew(async() => 
    { 
     Console.WriteLine("Start"); 
     await Task.Delay(5000); 
     Console.WriteLine("Done"); 
    }); 
    t.Wait(); 
    Console.WriteLine("All done"); 
} 

Первый пример создает задачу, которая печатает "Start", ждет 5 секунд печатает «Готово», а затем завершает задачу. Я жду завершения задачи и затем распечатаю «Все сделано». Когда я запускаю тест, он делает так, как ожидалось.

Второй тест должен иметь такое же поведение, за исключением того, что ожидание внутри задачи должно быть неблокирующим из-за использования async и ожидания. Но этот тест просто печатает «Старт», а затем сразу «Все сделано» и «Готово» никогда не печатается.

Я не знаю, почему я получаю такое поведение: S Любая помощь будет оценена очень :)

+0

Task.Delay неблокирующая. Я не вижу причин, по которым вы бы использовали вторую конструкцию. –

+0

@RoyDictus у них обоих есть свои проблемы. Вы никогда не должны вызывать 'Task.Wait()' – Gusdor

+0

возможный дубликат [Ожидание async/ожидание внутри задачи] (http://stackoverflow.com/questions/24777253/waiting-for-async-await-inside-a- task) – i3arnon

ответ

27

Второй тест состоит из двух вложенных задач и вы ждете внешней один, чтобы исправить это, вы должны использовать t.Result.Wait(). t.Result получает внутреннюю задачу.

Второй метод примерно соответствует этому:

public void TestAwait() 
{ 
    var t = Task.Factory.StartNew(() => 
      { 
       Console.WriteLine("Start"); 
       return Task.Factory.StartNew(() => 
       { 
        Task.Delay(5000).Wait(); Console.WriteLine("Done"); 
       }); 
      }); 
      t.Wait(); 
      Console.WriteLine("All done"); 
} 

Позвонив t.Wait() вас ждут внешней задачи, которая возвращается немедленно.


Предельно «правильный» способ справиться с таким сценарием, чтобы отказаться от использования Wait на все и просто использовать await. Wait может вызвать deadlock issues после того, как вы подключили пользовательский интерфейс к вашему асинхронному коду.

[Test] 
    public async Task TestCorrect() //note the return type of Task. This is required to get the async test 'waitable' by the framework 
    { 
     await Task.Factory.StartNew(async() => 
     { 
      Console.WriteLine("Start"); 
      await Task.Delay(5000); 
      Console.WriteLine("Done"); 
     }).Unwrap(); //Note the call to Unwrap. This automatically attempts to find the most Inner `Task` in the return type. 
     Console.WriteLine("All done"); 
    } 

Даже лучше всего использовать Task.Run пнуть вашу асинхронную операцию:

[TestMethod] 
    public async Task TestCorrect() 
    { 
     await Task.Run(async() => //Task.Run automatically unwraps nested Task types! 
     { 
      Console.WriteLine("Start"); 
      await Task.Delay(5000); 
      Console.WriteLine("Done"); 
     }); 
     Console.WriteLine("All done"); 
    } 
+2

Спасибо, что сработало :) Кстати, всегда хорошо использовать Task.Run вместо Task.Factory.StartNew или есть случаи, когда мне понадобится Task.Factory.StartNew, что Task.Run не может справиться? :) – svenskmand

+0

@svenskmand см. Http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx – brz

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