[英]ASP.NET MVC - Why are these async tasks running immediately?
我有一個ASP.NET MVC異步操作方法,如下所示:
public async Task<ActionResult> IndexAsync()
{
var tasks = new List<Task<string>>
{
GetSomethingAsync("a"),
GetSomethingAsync("b")
};
await Task.WhenAll(tasks);
return View();
}
private async Task<string> GetSomethingAsync()
{
var data = await _someService.GetSomethingAsync().ConfigureAwait(false);
return data.SomeData;
}
現在,當我調試並逐步tasks
變量的創建時,任務將立即執行。 換句話說,當我將鼠標懸停在await
行中的tasks
時,他們說“ RanToCompletion”。
為什么?
根據我的理解,應該創建任務,但這些任務應處於“ WaitingForActivation”狀態,直到由await Task.WhenAll(tasks)
阻止調用觸發。
有人可以向我解釋發生了什么嗎? 我之前已經寫過這樣的代碼,它通常可以按預期工作,所以我想知道這是ASP.NET還是ASP.NET MVC異步控制器?
TIA。
編輯如果我將代碼更改為:
var tasks = new List<Task<string>>
{
Task.Run(() => GetSomethingAsync("a")),
Task.Run(() => GetSomethingAsync("b"))
};
該方法按預期運行(直到await
才執行任務)。
在運行異步任務之前,我通常從不需要這樣做,而ASP.NET MVC是否需要這樣做?
根據您的評論,您實際上沒有任何真正的異步代碼-因此確實,任務將同步返回並處於完成狀態。
使方法真正異步的最簡單方法是await Task.Yield()
。 對於單元測試或由於某種原因必須異步但不占用大量時間的方法而言,這很好。 如果您需要運行慢速(阻塞或僅占用大量CPU的)方法-按照您的問題進行Task.Run
是使任務在單獨的線程上運行的合理方法。
筆記
async
本身不會使其異步,也不會await
自己創建任何線程。 await
”方法將無法找到要在其上運行的線程。 ConfigureAwait(false)
不能防止ASP.Net中基於負載的死鎖,並且可以方便地釋放HttpContext.Current
和線程的CultureInfo
謹慎地在ASP.Net中使用它,尤其是這樣做基本上沒有好處(恢復上下文的成本)與WPF / WinForm跨線程調用相比,新線程上的線程數非常低。 現在,當我調試並逐步完成任務變量的創建時,任務將立即執行。 換句話說,當我將鼠標懸停在等待行中的任務上時,他們說“ RanToCompletion”。
我建議您閱讀我的async
介紹 。 引用:
異步方法的開始與其他方法一樣執行。 也就是說,它會同步運行,直到達到“ await”(或引發異常)為止。
因此,如果您有殘存的異步方法返回已完成的任務,則您的方法調用(例如, GetSomethingAsync("a")
)將同步完成。 任務在添加到列表時已經完成。
根據我的理解,應該創建任務,但這些任務應處於“ WaitingForActivation”狀態,直到由await Task.WhenAll(tasks)阻止調用觸發。
WaitingForActivation
是一個不幸的名字。 對於Promise Tasks, WaitingForActivation
狀態表示它實際上已經在進行中 。
Task.WhenAll
或await
不需要進行任何“觸發”。 由Task.Run(() => GetSomethingAsync("a"))
創建的任務已經開始 。
可以在調試器中通過插入await Task.Delay(1000);
來觀察到這一點await Task.Delay(1000);
在await Task.WhenAll
之前,並檢查該延遲后任務的狀態。
ASP.NET MVC中需要這樣做嗎?
不。實際上, 您應該避免在ASP.NET上使用Task.Run
。 引用我在異步ASP.NET上的MSDN文章:
您可以通過等待Task.Run開始一些后台工作,但是這樣做沒有任何意義。 實際上,這實際上會干擾ASP.NET線程池啟發式方法,從而損害您的可伸縮性。 如果在ASP.NET上有CPU限制的工作要做,那么最好的選擇就是直接在請求線程上執行它。 通常,不要將工作排隊到ASP.NET上的線程池中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.