C# 如果在阻塞代码下面一直使用.ConfigureAwait(false),那么阻塞异步调用后的代码是否会在相同的上下文中继续?

C# 如果在阻塞代码下面一直使用.ConfigureAwait(false),那么阻塞异步调用后的代码是否会在相同的上下文中继续?,c#,async-await,C#,Async Await,首先,我要说的是,我知道应该对整个堆栈使用wait/async,而不是块异步代码。我知道这会导致僵局 假设我有以下代码: public void SomeMethod() { var result = GetData().Result; var context2 = HttpContext.Current; } public async Task<string> GetData() { // ... do stuff var result = a

首先,我要说的是,我知道应该对整个堆栈使用wait/async,而不是块异步代码。我知道这会导致僵局

假设我有以下代码:

public void SomeMethod()
{
    var result = GetData().Result;

    var context2 = HttpContext.Current;
}

public async Task<string> GetData()
{
    // ... do stuff

    var result = await new HttpClient().GetStringAsync("https://stackoverflow.com").ConfigureAwait(false);

    var context1 = HttpContext.Current;

    // ... process result

    return processedResult; // processedResult could be whatever
}
在这种情况下,代码必须等待HTTP请求完成。因此context1将为null,因为在请求完成后,代码在任意线程上运行。这是因为.configureWaitFalse调用,它必须等待请求完成

从重新搜索和测试来看,context2似乎总是有一个值,而不是空值。根据我的推理,这是合乎逻辑的。.Wait、.Result或.GetAwaiter.GetResult将阻塞该线程,然后继续该线程。然而,我还没有找到明确的文档说明这一点。也许我找错地方了,或者它太基本了,没有真正写在任何地方。我的意思是,为什么它会突然改变线程?我想我很奇怪,因为.configureWaitFalse之后的代码运行在任何其他线程上。context2是否有可能为空?

行var result=GetData.result;将导致当前线程被阻塞,直到异步操作GetData完成。当线程恢复时,HttpContext.Current将具有与以前相同的值,除非注释//表示的代码。。。do stuff已将其显式设置为null,如下所示:

HttpContext.Current = null;
行var result=GetData.result;将导致当前线程被阻塞,直到异步操作GetData完成。当线程恢复时,HttpContext.Current将具有与以前相同的值,除非注释//表示的代码。。。do stuff已将其显式设置为null,如下所示:

HttpContext.Current = null;
因此context1将为null,因为在请求完成后,代码在任意线程上运行

它将为null,因为它在线程池上下文而不是ASP.NET请求上下文上运行。线程与此无关

从重新搜索和测试来看,context2似乎总是有一个值,而不是空值

是的,在该上下文中阻塞当前线程将保持相同的上下文,如所述

但是,如果您执行以下操作,它也永远不会为空:

public async Task SomeMethod()
{
  var result = await GetData();
  var context2 = HttpContext.Current;
}
使用wait是推荐的模式。不仅是为了避免死锁,而且也是为了创造机会。换句话说,在异步代码上阻塞首先否定了异步代码的所有好处。异步代码的全部目的是释放一个线程,但是如果调用代码阻塞一个线程直到它完成,那么一个线程无论如何都会被用完

在ASP.NET pre-Core中,有一些场景中,阻塞是不可避免的子操作和MVC筛选器,而不是WebApi筛选器。我想说,只有在这些地方,阻塞是可以接受的;除此之外,您应该一直使用异步

因此context1将为null,因为在请求完成后,代码在任意线程上运行

它将为null,因为它在线程池上下文而不是ASP.NET请求上下文上运行。线程与此无关

从重新搜索和测试来看,context2似乎总是有一个值,而不是空值

是的,在该上下文中阻塞当前线程将保持相同的上下文,如所述

但是,如果您执行以下操作,它也永远不会为空:

public async Task SomeMethod()
{
  var result = await GetData();
  var context2 = HttpContext.Current;
}
使用wait是推荐的模式。不仅是为了避免死锁,而且也是为了创造机会。换句话说,在异步代码上阻塞首先否定了异步代码的所有好处。异步代码的全部目的是释放一个线程,但是如果调用代码阻塞一个线程直到它完成,那么一个线程无论如何都会被用完


在ASP.NET pre-Core中,有一些场景中,阻塞是不可避免的子操作和MVC筛选器,而不是WebApi筛选器。我想说,只有在这些地方,阻塞是可以接受的;除此之外,您应该一直使用异步。

您似乎在问,如果我阻止一个线程,然后取消阻止,以下代码是否仍在同一个线程上?这似乎是一个奇怪的问题。也许这可能与依赖项注入有关。如果你做了Transient like,你能确定范围并尝试一下吗?@Damien_The_unsiver我猜不确定性来自异步代码在另一个线程中继续的事实。你似乎在问如果我阻塞一个线程,然后取消阻塞,下面的代码还会在同一个线程上吗?,这似乎是一个奇怪的问题。也许这可能与依赖注入有关。如果你做了Transient like,你能确定范围并尝试一下吗?@Damien_The_unsivers我猜不确定性来自异步代码在另一个线程中继续的事实。你会如何定义线程池上下文?我发现自己不大可能成功
准确地定义它。HttpContext对象将为null,这与ASP.NET请求上下文中的情况相反,但不是更糟吗?是HttpContext保留ASP.NET请求上下文的所有状态吗?@ptf:线程池上下文是仅在线程池上运行continuations的默认上下文。它与ASP.NET请求上下文不同;ASP.NET请求上下文也在线程池线程上运行,但与请求上下文一起运行。请求上下文包括HttpContext.Current和其他一些东西,比如线程文化,如果您使用它,我相信模拟。线程池上下文定义得很好;ASP.NET请求上下文未在任何地方定义。如何定义线程池上下文?我发现自己不太能简明扼要地给它下定义。HttpContext对象将为null,这与ASP.NET请求上下文中的情况相反,但不是更糟吗?是HttpContext保留ASP.NET请求上下文的所有状态吗?@ptf:线程池上下文是仅在线程池上运行continuations的默认上下文。它与ASP.NET请求上下文不同;ASP.NET请求上下文也在线程池线程上运行,但与请求上下文一起运行。请求上下文包括HttpContext.Current和其他一些东西,比如线程文化,如果您使用它,我相信模拟。线程池上下文定义得很好;ASP.NET请求上下文没有在任何地方定义。