2013-08-26 55 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... 

而且從來沒有得到任何進一步。我試過並試圖理解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

如果你明確地創建了任務,那麼我認爲如果你像使用DoIOWorkFiveTimesAsync一樣將函數定義爲'async',它會將該函數包裝到'Task'中並自動啓動它(編譯器生成必要的代碼) 。 – CodingGorilla

+3

@Motig通常,使用'Task.Run'來返回一個已經開始的任務,而不是依賴任何爲你開始任務的任務。在早期預覽中,等待會開始執行任務,但不再執行任務,並假定它正在運行。 '新的任務'幾乎總是一個壞主意... –

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); 
}