首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么ASP.NET核心Web中没有这种死锁?

为什么ASP.NET核心Web中没有这种死锁?
EN

Stack Overflow用户
提问于 2018-02-04 08:48:05
回答 2查看 3.3K关注 0票数 11

我读过Stephen 的文章不要阻止异步代码,所以我创建了一个ASP.NET Core 项目:

代码语言:javascript
运行
复制
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;阻塞的请求上下文。但是它没有死锁,没有问题地返回!ASP.NET核心网络API的行为是否不同?

我用的是dotnet --info

代码语言:javascript
运行
复制
.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 console应用程序:

代码语言:javascript
运行
复制
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);完成,为了恢复,DoSomethingAsync()需要输入被阻塞的主线程的上下文。但实际上它也没有死锁。我哪里错了?

更新

正如其他人所指出的,ASP.NET Core & console applications中不存在同步上下文,现在我的问题是,与传统ASP.NET应用程序一样,当等待的异步操作完成并恢复运行时,同步上下文负责在延续时恢复HttpContext.Current之类的内容,那么ASP.NET Core应用程序如何在新选择的线程池线程上恢复之后,才能使HttpContext.Current这样的东西可用呢?

此外,对于没有自己的复杂线程的任何操作,假设它运行在线程池线程(如ASP.NET应用程序、ASP.NET核心应用程序等)上。并等待另一个异步操作。当它开始等待时,它会生成当前正在运行的线程。但是,一旦等待的异步操作完成,它将在另一个线程池线程上恢复,之前的线程上下文(如局部变量等)如何才能恢复?能恢复到新挑选的吗?例如,在下面的代码中,在var result = await DoSomethingAsync();之后有一个新线程来自为rest代码服务的线程池。那么它如何恢复nameage,然后return new string[] { $"{name} at {age}: {result}" };才能使用它们呢?局部变量存储在属于特定线程的线程调用堆栈中。因此,我认为必须有线程上下文切换来继续。在await调用之前,需要存储当前线程池线程的线程上下文,在await调用之后,需要将存储的线程上下文还原到新选择的线程上下文。如果是这样的话,成本将不便宜。我的理解对吗?

代码语言:javascript
运行
复制
[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}" };
}
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48606313

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档