.Net 核心 & SynchronizationContext & Thread.SetData

.Net core & SynchronizationContext & Thread.SetData

据我所知,AspNetCore doesn't have SynchronizationContext .

That “re-entering” the request context involves a number of housekeeping tasks, such as setting HttpContext.Current and the current thread’s identity and culture.

所以我创建了一个简单的 .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"));
    }

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

此外,当我使用 ConfigureAwait(false) 时,我在 res.

中得到了 null

所以现在我很困惑。因为ConfigureAwait

问题:

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

您正在 Thread 上调用 SetData。你怎么会认为它是 SynchronizationContext.

的一部分

您可以通过检查 SynchronizationContext.Current 的值轻松测试是否存在当前 SynchronizationContext - 如果它是 null,则没有 SynchronizationContext

您为测试该代码发出了多少个并发请求?

SynchronizationContext 或不是 framework/runtime 流动上下文的方式(就像在 AsyncLocal<T> 这样的类型中)是通过 ExecutionContext 数据,而不是 Thread数据。

I was surprised because I believe that SetData was part of the synchronization context. (which should not exist in asp.net core)

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

More, when I used ConfigureAwait(false) , I got null in res.

根据您 运行 此代码的时间、服务器的繁忙程度等,您可能会得到 null4 有或没有 ConfigureAwait(false)

If asp.net core doesn't have a SynchronizationContext, then why did 4 was available after await ?

这是一个特定于线程的值。 ASP.NET Core 上没有 SynchronizationContext,您的代码将在任何可用的线程池线程上恢复。如果该线程 碰巧 是启动该方法的同一个线程,那么 TLS 将仍然存在,因为它是针对该特定线程的。

相同的行为实际上适用于 ASP.NET pre-Core。在那种情况下,有一个 SynchronizationContext,但该上下文未绑定到任何特定线程。就像 ASP.NET Core 一样,ASP.NET pre-Core 上的异步方法可以在任何可用的线程池线程上恢复,因此 TLS 数据在 await.[=22= 之后可能存在也可能不存在。 ]

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