c# - 从异步方法设置时 AsyncLocal 的值不正确
问题描述
AsyncLocal
当从类的异步方法设置时,为什么不保留字段的值。考虑这个例子:
var scope = new TestScope();
// The default value is 0
Console.WriteLine(scope.Counter.Value);
// Setting the vlaue to 2
await scope.SetValueAsync();
Console.WriteLine(scope.Counter.Value);
class TestScope
{
public readonly AsyncLocal<int> Counter = new AsyncLocal<int> { Value = 0 };
public async Task SetValueAsync()
{
this.Counter.Value = 2;
await Task.Yield();
}
}
预期的输出应该是:
0
2
但实际情况是:
0
0
为什么退出SetValueAsync
方法时会更改异步上下文?
解决方案
这是因为 AsyncLocal 具有写时复制语义。基本上,当从内部异步范围更改时,会生成值的副本并且不会修改原始对象。
您可以通过将值包装在引用对象中来解决此问题。那是因为即使你复制了一个引用,你最终仍然在操作同一个对象:
class TestScope
{
public readonly AsyncLocal<StrongBox<int>> Counter = new AsyncLocal<StrongBox<int>> { Value = new StrongBox<int>(0) };
public int Value
{
get => Counter.Value.Value;
set => Counter.Value.Value = value;
}
public async Task SetValueAsync()
{
this.Value = 2;
await Task.Yield();
}
}
static async Task Test()
{
var scope = new TestScope();
// The default value is 0
Console.WriteLine(scope.Value);
// Setting the value to 2
await scope.SetValueAsync();
Console.WriteLine(scope.Value);
}
StrongBox<T>
只是将值类型包装在引用类型中的一种便捷方式。但是任何其他引用类型都可以做到这一点。
推荐阅读
- mysql - 问题:无法关闭 macOS 上的 MAMP 服务器
- go - 注意 for Go 循环中的并发
- jmeter - 文件名中的属性时,没有使用 Taurus 生成摘要报告
- tensorflow - TensorFlow 和 PyTorch 中的 Conv2D 填充
- javascript - Testcafe 从域中获取所有 Cookie,将它们存储在 Object / Array 中并检查 Cookie 的名称是否在数组中
- c# - 我正在制作一个 2d 平台游戏,这段代码让玩家可以无限跳转修复?
- asp.net-mvc - .NET 5 同一个程序集中的多个项目
- java - oracle 中的同义词
- php - 特殊字符德语未在 PHP 上显示
- python - 将元素添加到嵌套字典,其中值是向量列表