2017-07-28 248 views
4

這是我的實際代碼:爲什麼不等待?

async Task getData() 
    { 
     Thread.Sleep(5000); 
     Console.WriteLine("Step 1"); 

     using (HttpClient api = new HttpClient()) 
      await api.GetAsync("http://google.com/").ContinueWith(
       (getTask) => 
        Console.WriteLine(getTask.Result.StatusCode); 
      ); 

     Console.WriteLine("Step 2"); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     Task<Task> task = new Task<Task>(getData); 
     task.Start(); 
     task.Wait(); 
     Console.WriteLine("Step 3"); 
    } 

我得到以下輸出:

Step 1 
Step 3 
OK 
Step 2 

爲什麼Step 3不來Step 2後?

如何讓它按順序工作,即只返回到getData的調用者,直到getData中的所有內容完成爲止?

+2

嘗試'task.Result.Wait()',但你的例子似乎有點過於複雜。 –

+0

謝謝!有用。可以解釋爲什麼?如何控制流程繞過getData方法的結尾返回給調用者? –

+3

看起來你應該真正閱讀/通過正確的介紹異步/等待(例如[這個](https://blog.stephencleary.com/2012/02/async-and-await.html)例如) 。簡而言之:'getData'已經返回一個任務,通過將它包裝在另一個任務中,你必須等待內部任務。或者直接在'button1_Click'中寫'await getData(...)'。但要小心,異步/等待還有更多 - 真正閱讀更多內容。 –

回答

4

你也應該慶祝你的事件處理程序爲async

private async Task button1_Click(object sender, EventArgs e) 

await代替Wait

private async Task button1_Click(object sender, EventArgs e) 
{ 
    await getData(); 

    Console.WriteLine("Step 3"); 
} 

當我們使用異步/ AWAIT模式,我們應該走這條路,直到第一方法啓動它。否則,通過明確調用WaitResult,我們可能會遇到死鎖問題。此外,顯式調用這些方法可以阻止正在執行的線程。所以你放棄了使用async/await的主要好處,它不會阻塞正在執行的線程,並在一個單獨的線程上運行一些代碼,並且一旦完成,就會從停止的地方繼續執行代碼。

+0

謝謝。我不知道一個事件處理程序可以是'async'。這是否意味着所有調用事件處理程序的代碼也是'async'? –

+0

@歡迎您。這意味着可以異步處理事件而不會阻止您的應用程序。例如,如果我們說WPF應用程序,並且按鈕單擊會觸發網絡調用,需要花費相當長的時間才能完成,那麼如果相應的處理程序不是異步處理程序,則您的UI將凍結。 – Christos

2

要簡單明瞭地嘗試和放置東西 - async Task(和<T>)方法本身負責分配代表其完成的對象Task

如果你發現自己與async方法工作分配Task自己的對象(無論是直接,因爲在這裏,或者使用靜態工廠方法,如Task.Run),你一定要認識到,不止一個Task對象現在存在。你必須小心,並認識到你創建Task的情況(如這裏),他們自己現在返回Task s。

這是好得多,如果可能的話,擁抱async一路(如要修改的每個函數爲async,你會那麼容易找到每個調用點,使該位置async爲好),並停止分配任何Task是你自己。

相關問題