我读过Stephen 的文章不要阻止异步代码,所以我创建了一个ASP.NET Core 项目:
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
.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应用程序:
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代码服务的线程池。那么它如何恢复name、age,然后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}" };
}https://stackoverflow.com/questions/48606313
复制相似问题