【问题标题】:.Net core & SynchronizationContext & Thread.SetData.Net core & SynchronizationContext & Thread.SetData
【发布时间】:2019-12-07 04:57:57
【问题描述】:

据我所知,AspNetCore doesn't have 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"));
    }

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

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

所以现在我很困惑。因为ConfigureAwaitshouldn't have effect in asp.net core

问题:

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

【问题讨论】:

    标签: c# asp.net-core async-await synchronizationcontext


    【解决方案1】:

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

    没有; SetData 是线程本地存储 (TLS)。因此,它与特定线程相关联。这与同步上下文没有任何关系。

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

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

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

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

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

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

    【讨论】:

    • 同步上下文中不是包含文化信息数据等吗?这就是为什么它也包含 tls
    • @RoyiNamir:ASP.NET(核心前)SyncCtx 包含当前请求/页面的文化。这是唯一包含该内容的 SyncCtx;其他人都没有。除了 ASP.NET (pre-Core) SyncCtx 中的文化之外,每个线程 有自己的文化和“UI 文化”。
    • @JayShah:旧的 ASP.NET 方法是将它们设置为静态 HttpContext.Current 属性。该属性在 ASP.NET Core 上不存在。使用 Core,所有 cookie、查询字符串和其他特定于请求/响应的数据都是局部变量,而不是静态变量。
    • @YuriCardoso:在 ASP.NET Core 上没有 HttpContext.Current 属性。局部变量是在方法中定义的,以及隐含的this
    • @AdrianNasui:AsyncLocal&lt;T&gt; 类型提供了异步感知范围。它大致相当于旧的logical call context。我怀疑(但尚未验证).NET Core DI 使用此技术来确定“当前”范围。我确实知道 .NET Core 日志记录范围确实使用了这种技术。
    【解决方案2】:

    您正在对Thread 调用SetData。你怎么会认为它是SynchronizationContext 的一部分。

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

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

    SynchronizationContext 或不是框架/运行时流动上下文的方式(如AsyncLocal&lt;T&gt; 之类的类型)是通过ExecutionContext 数据,而不是Thread 数据。

    【讨论】:

    • 同步上下文中不是包含文化信息数据等吗?这就是为什么它也包含 tls
    • 你从哪里得到这个想法的? SynchronizationContext 只是关于同步到一个共同的上下文。
    猜你喜欢
    • 2020-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多