簡體   English   中英

在基於 UI 的應用程序中使用 await Task.Run(() => someMethodAsync()) 與 await someMethodAsync()

[英]Using await Task.Run(() => someMethodAsync()) vs await someMethodAsync() in a UI based app

我用這個例子閱讀了這篇文章

class MyService
{
  /// <summary>
  /// This method is CPU-bound!
  /// </summary>
  public async Task<int> PredictStockMarketAsync()
  {
    // Do some I/O first.
    await Task.Delay(1000);

    // Tons of work to do in here!
    for (int i = 0; i != 10000000; ++i)
      ;

    // Possibly some more I/O here.
    await Task.Delay(1000);

    // More work.
    for (int i = 0; i != 10000000; ++i)
      ;

    return 42;
  }
}

然后描述了如何根據您使用的是基於 UI 的應用程序還是 ASP.NET 應用程序來調用它:

//UI based app:
private async void MyButton_Click(object sender, EventArgs e)
{
  await Task.Run(() => myService.PredictStockMarketAsync());
}

//ASP.NET:
public class StockMarketController: Controller
{
  public async Task<ActionResult> IndexAsync()
  {
    var result = await myService.PredictStockMarketAsync();
    return View(result);
  }
}

為什么需要使用Task.Run() PredictStockMarketAsync()在基於 UI 的應用程序中執行PredictStockMarketAsync()

不會使用await myService.PredictStockMarketAsync(); 在基於 UI 的應用程序中也不會阻塞 UI 線程?

默認情況下,當您await未完成的操作時,將捕獲同步上下文(如果存在)。 然后,當異步工作完成后重新激活時,捕獲的同步上下文用於編組工作。 許多場景沒有同步上下文,但諸如 winforms 和 WPF 之類的 UI 應用程序,並且同步上下文代表 UI 線程(基本上:這是為了使默認行為變為“我的代碼有效”而不是“我在我的async方法中與 UI 對話時獲得跨線程異常”)。 本質上,這意味着當您從 UI 線程await Task.Delay(1000) ,它會暫停 1000 毫秒(釋放 UI 線程),然后在 UI 線程上恢復。 這意味着您“在這里要做大量工作”發生在 UI 線程上,阻塞了它。

通常,對此的修復很簡單:添加.ConfigureAwait(false) ,它禁用同步上下文捕獲:

await Task.Delay(1000).ConfigureAwait(false);

(通常:在該方法中的所有await之后添加此內容)

請注意,只有在您知道不需要同步上下文提供的內容時才應該這樣做。 特別是:之后您不會嘗試觸摸 UI。 如果確實需要與 UI 對話,則必須明確使用 UI 調度程序。

當您使用Task.Run(...) ,您通過不同的路由轉義了同步上下文 - 即通過不在 UI 線程上啟動(同步上下文是通過活動線程指定的)。

暫無
暫無

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

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