簡體   English   中英

為什么ASP.NET Core Web API中沒有這種死鎖?

[英]Why doesn't this deadlock in ASP.NET Core Web API?

我讀過Stephen Cleary的帖子Do not Block on Async Code ,所以我創建了一個ASP.NET Core Web API項目:

class AsyncTest
{
    public async Task<string> DoSomethingAsync()
    {
        await Task.Delay(3000);
        return "I'm back";
    }
}

[Route("api/[controller]")]
public class ValuesController : Controller
{
    // GET api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        var asyncTest = new AsyncTest();
        var result = asyncTest.DoSomethingAsync().Result;
        return new string[] { result };
    }
}

我預計這段代碼會陷入僵局,因為曾經await Task.Delay(3000); 完成后, DoSomethingAsync()需要輸入被var result = asyncTest.DoSomethingAsync().Result;阻止的請求上下文var result = asyncTest.DoSomethingAsync().Result; 但它沒有死鎖並且沒有問題就返回! ASP.NET Core Web API的行為是否不同?

我正在使用dotnet --info

.NET Command Line Tools (2.1.2)

Product Information:
 Version:            2.1.2
 Commit SHA-1 hash:  5695315371

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.14393
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\2.1.2\

Microsoft .NET Core Shared Framework Host

  Version  : 2.0.3
  Build    : a9190d4a75f4a982ae4b4fa8d1a24526566c69df

我還創建了一個普通的.NET Framework 4.6.1 控制台應用程序:

class Program
{
    static void Main(string[] args)
    {
        var asyncTest = new AsyncTest();

        var result = asyncTest.DoSomethingAsync().Result;
    }
}

class AsyncTest
{
    public async Task<string> DoSomethingAsync()
    {
        await Task.Delay(3000);
        return "I'm back";
    }
}

我認為這也應該是死鎖,因為var result = asyncTest.DoSomethingAsync().Result; 阻塞主線程, DoSomethingAsync()await Task.Delay(3000);上捕獲主線程的上下文await Task.Delay(3000); await Task.Delay(3000); 完成后,為了恢復, DoSomethingAsync()需要輸入被阻塞的主線程的上下文。 但它實際上也沒有死鎖。 我錯在哪里?

更新

正如其他人所指出的, ASP.NET Core控制台應用程序中沒有同步上下文 ,現在我的問題是,在傳統的ASP.NET應用程序中,同步上下文負責在繼續時恢復HttpContext.Current之類的事情。等待的異步操作完成並且exectution重新開始,那么一旦ASP.NET核心應用程序在新挑選的線程池線程上恢復后,它如何使這些東西像HttpContext.Current一樣可用?

此外,對於任何沒有自己的精巧線程的操作,假設它在線程池線程(如ASP.NET應用程序ASP.NET核心應用程序等)上運行,並等待另一個異步操作。 當它開始等待時,它會產生它當前正在運行的線程。 但是,一旦等待的異步操作完成,它將在另一個線程池線程上恢復,如何將先前的線程上下文(如局部變量等)恢復到新選擇的線程上? 例如,在下面的代碼中,在var result = await DoSomethingAsync(); 服務於其余代碼的線程池中有一個新線程。 那么它如何恢復nameage ,然后return new string[] { $"{name} at {age}: {result}" }; 可以用嗎? 局部變量存儲在屬於特定線程的線程調用堆棧中。 所以我認為必須有繼續的線程上下文切換 await調用之前,需要存儲當前線程池線程的線程上下文,在await調用之后,需要將存儲的線程上下文恢復到新挑選的線程上下文。 如果是這樣,成本將不便宜。 我的理解在這里是否正確?

[HttpGet]
public async Task<IEnumerable<string>> GetAsync()
{
    var name = "John Doe";
    var age = 20;
    var result = await DoSomethingAsync();
    return new string[] { $"{name} at {age}: {result}" };
}

因為ASP.NET Core沒有同步上下文。

更新

Jon Skeet有一個很棒的博客系列,如果你想了解它的工作原理: https//codeblog.jonskeet.uk/category/eduasync/

對於ASP.NET Core, 沒有SynchronizationContext ,這意味着在ASP.NET Core中不會發生指定的阻塞情況。 控制台應用也是如此。

暫無
暫無

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

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