簡體   English   中英

ASP.NET MVC-為什么這些異步任務立即運行?

[英]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自己創建任何線程。
  • 最好使用真正的異步方法進行網絡調用。 ASP.Net具有有限的線程拉取,並且用於阻塞調用的消耗線程將耗盡負載下的拉取,導致死鎖,因為“ 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.WhenAllawait不需要進行任何“觸發”。 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.

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