AsyncLocal<T> 在非 async/await 代码中有什么作用?

What's the effect of AsyncLocal<T> in non async/await code?

我正在处理一个非常大且旧的桌面 winform 应用程序代码库。在此代码库中,有很多操作在后台线程中执行,主要使用 BackgroundWorker.

此代码库中的一个常见模式是通过将工件绑定到正在执行的线程来隐藏复杂性。例如,数据库连接和事务存储在 [ThreadStatic] 字段中。

我正在尝试改变这一点,并开始使用 async/await 代码,并受益于 运行 池中任何线程中的任务,并允许任务继续在任何其他线程中执行使用 ConfigureAwait(false) 线程。我知道 [ThreadStatic] 不能很好地与 async/await 搭配使用,而且我在这里阅读了几个建议改用 AsyncLocal<T> 的答案。

鉴于我正在处理大型代码库,如前所述,我无法一次性切换到 async/await,我必须逐步进行此更改。因此,之前具有 [ThreadStatic] 的代码将更改为 AsyncLocal<T>,但大部分代码将继续使用 BackgroundWorker,并且不会命中单个 async/await 行代码。

问题
这行得通吗?我需要能够定义某种可以与我的新 async/await 代码一起使用的上下文流,并且还需要继续使用我的旧非异步代码,这些代码依赖于 [ThreadStatic] 保持每个线程的内容独立于每个线程其他.

如果我完全错了,走错了路,欢迎提出建议。

应该可以。

AsyncLocal<T>是逻辑调用上下文的抽象。我在旧博客post.the logical call context and how it interacts with async/await中详细描述了the logical call context and how it interacts with async/await

总而言之,它可能会很好地工作,但是 AsyncLocal<T> 有一个方面与 ThreadStatic 完全不同。

当您写入 AsyncLocal<T> 值时,会为当前逻辑调用上下文设置该值。 async 方法将为其逻辑调用上下文建立一个写时复制作用域,因此如果您在 中 写入一个 async 方法,它将创建包含新值的 new 逻辑调用上下文。这允许 async 方法以嵌套方式使用它,其中 "inner" 上下文可以覆盖 "outer" 上下文。 但是, "inner" 上下文值永远不会流回调用者;当 "outer" 上下文恢复时,它完全取代了 "inner" 上下文。

如果 none 个方法是 async 并且值仅从它们自己的线程设置,则该线程只有一个逻辑调用上下文,并且 writing/reading 值将与 ThreadStatic.

一样工作