NET 4.6引入了AsyncLocal<T>
类,用于沿着异步控制流流动环境数据.我之前已经使用CallContext.LogicalGet/SetData
实现了这个目的,我想知道这两者在语义上是否以及在哪些方面是不同的(除了明显的API差异,比如强类型和不依赖字符串键).
NET 4.6引入了AsyncLocal<T>
类,用于沿着异步控制流流动环境数据.我之前已经使用CallContext.LogicalGet/SetData
实现了这个目的,我想知道这两者在语义上是否以及在哪些方面是不同的(除了明显的API差异,比如强类型和不依赖字符串键).
语义基本相同.两者都存储在ExecutionContext
中,并通过异步调用流动.
区别在于API更改(正如您所描述的)以及为值更改注册回调的能力.
从技术上讲,实现上有很大的不同,因为每次复制CallContext
时(使用CallContext.Clone
)都会克隆CallContext
,而AsyncLocal
的数据保存在ExecutionContext._localValues
字典中,只复制引用,不需要任何额外的工作.
为了确保当您更改AsyncLocal
的值时,更新只影响当前流,将创建一个新字典,并将所有现有值浅复制到新的字典中.
这种差异对性能可能是好的,也可能是坏的,这取决于AsyncLocal
的使用位置.
现在,正如Hans Passant在 comments 中提到的,CallContext
最初用于远程处理,在不支持远程处理的地方(例如Net Core)不可用,这可能就是为什么将AsyncLocal
添加到框架中:
#if FEATURE_REMOTING
public LogicalCallContext.Reader LogicalCallContext
{
[SecurityCritical]
get { return new LogicalCallContext.Reader(IsNull ? null : m_ec.LogicalCallContext); }
}
public IllogicalCallContext.Reader IllogicalCallContext
{
[SecurityCritical]
get { return new IllogicalCallContext.Reader(IsNull ? null : m_ec.IllogicalCallContext); }
}
#endif
注意:VisualStudioSDK中还有一个AsyncLocal
,基本上是CallContext
的包装,它显示了这些概念的相似性:Microsoft.VisualStudio.Threading.