[英]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.