我正在研究桌面winform应用程序的一个非常大的旧代码库。在此代码库中,有许多操作在后台线程中执行,主要使用BackgroundWorker
。
此代码库中的一个常见模式是通过将工件绑定到正在执行的线程来隐藏复杂性。例如,数据库连接和事务存储在[ThreadStatic]
字段中。
我正在尝试更改它,并开始使用async/await
代码,并从在池的任何线程中运行任务中受益,并允许任务通过使用{{1在任何其他线程中继续执行}}。我知道ConfigureAwait(false)
对[ThreadStatic]
的效果不佳,我在这里读了几个答案,建议改为使用async/await
。
鉴于我正在开发大型代码库,如前所述,我无法一次性切换到AsyncLocal<T>
,我必须逐步进行此更改。因此之前具有async/await
的代码将更改为[ThreadStatic]
,但代码的大部分将继续使用AsyncLocal<T>
,并且不会遇到单个BackgroundWorker
代码行。
问题
这会有用吗?我需要能够定义一些可以使用我的新async/await
代码的上下文流程,并且还继续使用我的旧非异步代码,该代码依赖async/await
保持每个线程内容独立于每个其他
如果我完全错了,走错了路,建议非常受欢迎。
答案 0 :(得分:14)
它应该有用。
AsyncLocal<T>
是逻辑调用上下文的抽象。我在一篇旧博客文章中详细描述了the logical call context and how it interacts with async
/await
。
总之,它可能会正常工作,但AsyncLocal<T>
的一个方面与ThreadStatic
完全不同。
当您写入AsyncLocal<T>
值时,将为当前逻辑调用上下文设置该值。 async
方法将为其逻辑调用上下文建立写时复制范围,因此如果您在 async
方法中写入,它将创建一个包含新值的新逻辑调用上下文。这允许async
方法以嵌套方式使用它,其中&#34; inner&#34;上下文可以覆盖&#34;外部&#34;上下文。 然而,&#34;内部&#34;上下文值永远不会回流给调用者;当&#34;外部&#34;上下文恢复,它完全取代了&#34;内部&#34;上下文。
如果没有方法是async
且值只是从它们自己的线程设置,那么该线程只有一个逻辑调用上下文,写入/读取值将与{{ 1}}。