2 回答
TA贡献1848条经验 获得超2个赞
这是错误/缺失的功能还是有意的设计决定?
这是一个有意的设计决定。具体来说,async
状态机为其逻辑上下文设置“写时复制”标志。
与此相关的是所有同步方法都属于它们最近的祖先async
方法。
在编写依赖于 AsyncLocal 的代码时,我是否需要担心这种行为?比如说,我想编写我的 TransactionScope-wannabe,它通过等待点传输一些环境数据。这里 AsyncLocal 够用吗?
像这样的大多数系统都AsyncLocal<T>
结合了IDisposable
清除AsyncLocal<T>
值的模式。组合这些模式可确保它适用于同步或异步代码。AsyncLocal<T>
如果消费代码是一个async
方法,它自己会工作得很好;与它一起使用IDisposable
确保它可以同时使用async
和同步方法。
当涉及到在整个“逻辑代码流”中保留值时,.NET 中的 AsyncLocal 和 CallContext.LogicalGetData / CallContext.LogicalSetData 是否还有其他替代方案?
不。
TA贡献1789条经验 获得超8个赞
这对我来说似乎是一个有意的决定。
正如您已经知道的那样,它SetValueInAsyncMethod被编译成一个隐式捕获当前 ExecutionContext 的状态机。当您更改AsyncLocal-variable 时,该更改不会“流”回调用函数。相反,SetValueInNonAsyncMethod它不是异步的,因此没有编译成状态机。因此,不会捕获 ExecutionContext 并且对AsyncLocal-variables 的任何更改对调用者都是可见的。
如果您出于任何原因需要它,您也可以自己捕获 ExecutionContext:
private static Task SetValueInNonAsyncMethodWithEC()
{
var ec = ExecutionContext.Capture(); // Capture current context into ec
ExecutionContext.Run(ec, _ => // Use ec to run the lambda
{
asyncLocal.Value = 3;
PrintValue();
});
return Task.CompletedTask;
}
这将输出值 3,而 Main 将输出 2。
当然,简单地转换SetValueInNonAsyncMethod为异步让编译器为您做这件事要容易得多。
关于使用AsyncLocal(或就此而言CallContext.LogicalGetData)的代码,重要的是要知道更改调用的异步方法(或任何捕获的 ExecutionContext)中的值不会“回流”。但您当然仍然可以访问和修改AsyncLocal,只要您不重新分配它即可。
- 2 回答
- 0 关注
- 73 浏览
添加回答
举报