.Net 核心 & SynchronizationContext & Thread.SetData

Roy*_*mir 9 c# synchronizationcontext async-await asp.net-core

据我所知,AspNetCore没有 SynchronizationContext.

“重新进入”请求上下文涉及许多内务任务,例如设置 HttpContext.Current 和当前线程的身份和文化。

所以我创建了一个简单的 .Net Core Api 项目,并执行以下操作:

    [HttpGet]
    [Route("checkVar")]
    public async Task<IActionResult> checkVar()
    {
        Thread.SetData(Thread.GetNamedDataSlot("Random"),4);
        await Task.Delay(1000);
        var res = Thread.GetData(Thread.GetNamedDataSlot("Random"));
    }
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是,res它的价值为4. 我很惊讶,因为我相信这SetData是同步上下文的一部分。(在asp.net core中不应该存在)

更多,当我使用时ConfigureAwait(false),我进入nullres

所以现在我很困惑。因为ConfigureAwait 在asp.net core中不应该有影响

题:

如果 asp.net core 没有 SynchronizationContext,那么为什么在4之后可用await?为什么会ConfigureAwait在非 SynchronizationContext 环境中改变结果?

Ste*_*ary 13

我很惊讶,因为我相信 SetData 是同步上下文的一部分。(在asp.net core中不应该存在)

不; SetData是线程本地存储 (TLS)。所以它绑定到一个特定的线程。这与同步上下文没有任何关系。

更多,当我使用 ConfigureAwait(false) 时,我在 res 中得到了空值。

根据当您运行此代码,服务器的繁忙程度,等等,你可以得到null4有或无ConfigureAwait(false)

如果 asp.net core 没有 SynchronizationContext,那么为什么 4 在 await 之后可用?

这是一个线程特定的值。SynchronizationContextASP.NET Core上没有,您的代码将在任何可用的线程池线程上恢复。如果该线程恰好与启动该方法的线程相同,则 TLS 将仍然存在,因为它是针对该特定线程的。

相同的行为实际上适用于 ASP.NET pre-Core。在这种情况下,有一个SynchronizationContext,但该上下文不绑定到任何特定线程。就像 ASP.NET Core 一样,ASP.NET pre-Core 上的异步方法可以在任何可用的线程池线程上恢复,因此await.

为了用数据支持这一理论,请尝试Environment.CurrentManagedThreadId在 之前和之后进行日志记录await,看看存在的数据与保持不变的 id 之间是否存在任何相关性。

  • @YuriCardoso:ASP.NET Core 上没有“HttpContext.Current”属性。局部变量是在方法中定义的变量,以及隐式的“this”。 (2认同)