簡體   English   中英

為什么異步等待無法正常工作

[英]Why the async await not working as expected

我正在從教程中學習TPL(異步/等待),並嘗試使用控制台應用程序對其進行測試。 請不要被我的無知所冒犯。 我確定我在某處做錯了-我編寫了以下代碼:

static void Main(string[] args_)
{
    Task<int> task = ProcessNumber(25);
    Console.WriteLine(string.Format("{0}: Waiting started...", DateTime.Now));
    task.Wait();
    Console.WriteLine(string.Format("{0}: Waiting ended...", DateTime.Now));
    Console.WriteLine(task.Result);

    Console.WriteLine("Press any key to terminate!");
    Console.ReadLine();
}

static async Task<int> ProcessNumber(int i_)
{
    Thread.Sleep(1000);
    var integer = await IncrementNumber(i_ * 23);
    return integer;
}

static async Task<int> IncrementNumber(int j_)
{
    Thread.Sleep(6000);
    return (j_ + 23) / 23;
}

這是純C#控制台代碼。 我的問題是為什么我得到以下輸出:

3/5/2015 5:22:37 PM: Waiting started...
3/5/2015 5:22:37 PM: Waiting ended...
26

“等待開始”和“等待結束”之間是否應該有相當長的時間間隔?

更新

在回答之后,我發現Task.Delay(..)和Thread.Sleep(..)是不一樣的,因為它們的工作方式非常不同。 這是一個很好的鏈接 ,並舉例說明。

似乎將TPL視為另一種多線程框架是錯誤的。 所有的答案對我都有幫助,所以我投了贊成票。 但是,我選擇了喬恩的答案,因為這是最具說明性的,也是第一個出現的答案。 謝謝大家!

否,因為實際上您在打印“ Waiting started之前要睡眠7秒鍾。 這是發生了什么:

  • 主要電話ProcessNumber
  • ProcessNumber睡眠1秒
  • ProcessNumber調用IncrementNumber
  • IncrementNumber睡眠6秒
  • IncrementNumber執行計算,然后返回完成的任務
  • ProcessNumber等待完成的任務,然后繼續
  • ProcessNumber返回完成的任務
  • 主版畫“等待開始”
  • Main等待已完成的任務完成(無操作)
  • 主版畫“等待中”

如果將每個Thread.Sleep更改為

await Task.Delay(...);

然后您將看到您的期望。 新流程將是:

  • 主要電話ProcessNumber
  • ProcessNumber調用Task.Delay並等待結果...
  • ...並且由於尚未完成,ProcessNumber將正在進行的任務返回給Main
  • 主版畫“等待開始”
  • Main等待ProcessNumber返回的任務完成
  • Task.Delay任務完成
  • ProcessNumber中的繼續操作開始執行...
  • ProcessNumber調用IncrementNumber
  • IncrementNumber調用Task.Delay並等待結果...
  • ...並且由於尚未完成,因此IncrementNumber將正在進行的任務返回給ProcessNumber
  • ProcessNumber等待尚未完成的任務,因此繼續執行。
  • 第二個延遲任務完成
  • IncrementNumber中的延續執行
  • 它到達IncrementNumber的末尾,並設置關聯任務的結果
  • 現在執行ProcessNumber(正在等待該任務)的繼續
  • 它到達ProcessNumber的末尾,並設置關聯任務的結果
  • Main中對Task.Wait的調用完成
  • 主版畫“等待中”等

真正重要的是要理解,直到異步方法在實際上需要暫停的第一個await發生(因為等待狀態尚未完成)之前,它才同步執行。 這不像調用異步方法將其拆分為另一個線程一樣。

這是因為您的方法都不是異步的。 它們通過返回Task來偽裝成異步的,但是它們都是同步執行的。

實際上,您應該收到針對IncrementNumber號的編譯器警告,說明此異步方法缺少'await'運算符,並且將同步運行...等 它基本上說您的方法將同步執行。 這個答案詳細解釋了

因此,當ProcessNumber返回時,整個嵌套方法調用已經同步完成。

更改方法以使用await Task.Delay而不是Thread.Sleep使其異步。

您需要重構代碼。 像這樣

    static async Task<int> IncrementNumber(int j_)
{
    await Task.Delay(...);
    return (j_ + 23) / 23;
}
  1. 具有關鍵字async的函數在體內必須至少等待一個等待時間,以便運行函數async。
  2. Thread.Sleep(...)也對此負責。
  3. 如果找到CPU綁定任務而不是Thread.Sleep,則需要執行以下操作。

     //it will create a new thread then sleep. await Task.Run( () => ( CPUBoundTask()); var integer = await IncrementNumber(i_ * 23); return integer; 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM