2013-08-26 6 views
2

У меня есть следующие программы:Почему эта программа просто висит?

static void Main(string[] args) { RunTest(); } 

    private static void RunTest() { 
     DoIOWorkFiveTimesAsync().Wait(); 
    } 

    private static async Task DoIOWorkFiveTimesAsync() { 
     for (int i = 0; i < 5; ++i) { 
      Console.WriteLine("Before: " + i); 
      await DoIOWorkAsync(); 
      Console.WriteLine("After: " + i); 
     } 
    } 

    private static Task DoIOWorkAsync() { 
     Console.WriteLine("Doing work..."); 
     return new Task(() => Thread.Sleep(1500)); 
    } 

Я бы ожидать, чтобы увидеть:

Before: 1 
    Doing work... 
    After: 1 
    Before: 2 
    Doing work... 
    After: 2 
    Before: 3 
    Doing work... 
    After: 3 
    Before: 4 
    Doing work... 
    After: 4 
    Before: 5 
    Doing work... 
    After: 5 

Но вместо этого, он получает:

Before: 1 
Doing work... 

И никогда не получает дальше. Я попытался и попытался понять функции async/await в C# 5, но всегда не имел никакого эффекта. Опять же, объяснение ускользает от меня.

+0

Если вы имели 'SynchronizationContext' результат будет очевиден, блокировка ожидания предотвращает продолжений от быть запланированы, но поскольку вы не устанавливаете его, это не должно происходить ... – Servy

+1

Вы должны использовать 'Task.Delay' для создания задачи, которая будет выполнена за X миллисекунды вместо того, что вы делаете. Ваш метод блокирует поток на время ожидания. – Servy

ответ

3

Простой, вы вернули Task, но вы его не запустили.

Если вы измените свой код следующим образом:

private static Task DoIOWorkAsync() 
{ 
    Console.WriteLine("Doing work..."); 
    Task work = new Task(() => Thread.Sleep(1500)); 
    work.Start(); 
    return work; 
} 

Он работает, как и следовало ожидать.

+0

Хм ... Я предполагал, что это запустит задачу. Благодарю. – Xenoprimate

+0

Нет, если вы явно создаете задачу, я думаю, что если вы определите функцию как 'async', как вы это делали с' DoIOWorkFiveTimesAsync', она обертывает эту функцию в 'Task' и запускает ее автоматически (компилятор генерирует необходимый код) , – CodingGorilla

+3

@Motig В общем, это просто хорошая идея использовать «Task.Run», чтобы вернуть уже запущенную задачу, а не полагаться на что-либо, ставящее перед собой задачу. В ранних предварительных просмотрах ожидание запускает задачу, но она больше не делает и предполагает, что она запущена. 'new Task' почти всегда плохая идея ... –

9

Проблема в том, что вы используете return new Task(() => Thread.Sleep(1500)); вместо Task.Run.

new Task фактически не запускает задачу, которая приведет к тому, что await никогда не будет запускаться.

Вместо этого попробуйте:

private static Task DoIOWorkAsync() { 
    Console.WriteLine("Doing work..."); 
    return Task.Run(() => Thread.Sleep(1500)); 
} 

Или еще лучше:

private static async Task DoIOWorkAsync() { 
    Console.WriteLine("Doing work..."); 
    await Task.Delay(1500); 
} 
Смежные вопросы