.net core AsyncLocal 失去了价值

2023-12-01

我使用类似的模式HttpContext访问器

简化版本如下,Console.WriteLine(SimpleStringHolder.StringValue)不应该为空。

public class SimpleStringHolder
{
    private static readonly AsyncLocal<ValueHolder> CurrentHolder = new AsyncLocal<ValueHolder>();

    public static string StringValue
    {
        get => CurrentHolder.Value?.StringValue;

        set
        {
            var holder = CurrentHolder.Value;
            if (holder != null)
            {
                holder.StringValue = null;
            }

            if (value != null)
            {
                CurrentHolder.Value = new ValueHolder() { StringValue = value };
            }
        }
    }

    private class ValueHolder
    {
        public string StringValue;
    }
}
class Program
{
    private static readonly AsyncLocal<string> currentValue = new AsyncLocal<string>();

    public static void Main(string[] args)
    {
        var task = Task.Run(async () => await OutterAsync());
        task.Wait();
    }

    public static async Task OutterAsync()
    {
        SimpleStringHolder.StringValue = "1";
        await InnerAsync();
        Console.WriteLine(SimpleStringHolder.StringValue); //##### the value is gone ######
    }

    public static async Task InnerAsync()
    {
        var lastValue = SimpleStringHolder.StringValue;
        await Task.Delay(1).ConfigureAwait(false);
        SimpleStringHolder.StringValue = lastValue; // comment this line will make it work
        Console.WriteLine(SimpleStringHolder.StringValue); //the value is still here
    }
}

在上面的代码中,OutterAsync调用异步方法InnerAsync, in InnerAsync the StringValue被设置,这使得 AsyncLocal 失去它的上下文OutterAsync Console.WriteLine(SimpleStringHolder.StringValue);一片空白。

我认为神奇之处在于 SimpleStringHolder 的属性集,删除以下代码将使事情变得正确。

if (holder != null)
{
    holder.StringValue = null;
}

上面的代码按预期工作。

请帮我解释一下这是什么法术?


AsyncLocal<T>存在是为了提供一种在异步执行上下文中保存值的机制。关键是您的示例涉及两个因素:

  1. An await允许方法返回调用者,这可能会更改上下文。与年长的ThreadLocal<T>类型,当执行将控制权返回给方法时,它可能位于不同的线程中,即使来自async上下文的观点是相同的。使用AsyncLocal<T>确保上下文的状态在await可等待对象完成后,将控制权返回给该方法。
  2. 直到发生需要更改上下文的事情之前,对象的当前状态AsyncLocal<T>对象是之前的任何对象。 IE。方法本质上继承了对象被调用时所处的状态。如果您正在处理简单的值,则不会出现任何意外,但是对于像您这样的引用类型ValueHolder类型,唯一的东西AsyncLocal<T>正在跟踪的是参考到那个物体。仍然只有该对象的一份副本,并且对任何给定此类对象的状态的更改都会像它们在有或没有异步上下文浮动的情况下总是所做的那样工作(即,通过对该对象的任何引用都可以看到它们)。

因此,在您提供的代码示例中:

  1. OutterAsync()设置StringValue财产给"1",这会产生一个新的ValueHolder正在创建的对象,以及StringValue该对象的属性被设置为"1".
  2. OutterAsync() calls InnerAsync()。然后该方法检索string来自持有人的参考(间接......即通过SimpleStringHolder.StringValue财产)。由于此时尚未对值或上下文进行任何更改,因此相同ValueHolder在这种情况下使用对象,所以你得到"1" back.
  3. InnerAsync()等待一个异步任务,这会导致创建一个新的执行上下文,以隔离对任务所做的更改AsyncValue<T>反对该上下文。从此时起,对象的变化是not在不同的上下文中通过代码看到。例如,在OutterAsync() method.
  4. 异步任务完成后InnerAsync(),然后该方法将一个新值设置为SimpleStringHolder.StringValue财产。因为之前的上下文是继承的,当setter设置时holder.StringValue to null,它正在设置创建的对象的属性OutterAsync(). But…因为代码处于新的上下文中,所以当 setter 为CurrentHolder.Value属性,该更改与该上下文隔离。
  5. 当。。。的时候InnerAsync()方法最终完成,这完成了任务OutterAsync()方法await正在等待。这导致AsyncValue<T>将其状态恢复到OutterAsync()方法的上下文,与之前的上下文不同InnerAsync()当它更新了SimpleStringHolder.StringValue价值。具体来说,这个恢复的状态是对ValueHolder最初设置的对象SimpleStringHolder当。。。的时候holder.StringValue属性被设置为 null。
  6. 所以,当OutterAsync()然后查看属性值,发现它设置为null。因为它被设置为空。

在您自己的实验中,您可以完全删除空分配,或者简单地省略分配SimpleStringHolder.StringValue之后InnerAsync()'s await语句(因为如果不进行赋值,则永远不会执行空赋值)。无论哪种方式,都不会发生空分配,因此先前分配的值仍然存在。

但是如果你确实进行了空赋值,调用者OutterAsync()将恢复其上下文,然后恢复持有者对象引用,以及该持有者对象自己的引用string参考已经设置为null,所以这就是OutterAsync() sees.

相关阅读:
AsyncLocal 在非 async/await 代码中有何作用?
为什么代码稍微重构一下,AsyncLocal 会返回不同的结果?
Does AsyncLocal也做那些事情ThreadLocal does?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

.net core AsyncLocal 失去了价值 的相关文章

随机推荐

  • bash 中的转义字符(对于 JSON)

    我使用 git 然后将提交消息和其他位作为 JSON 有效负载发布到服务器 目前我有 MSG git log n 1 format oneline grep o 它将 MSG 设置为如下所示 Calendar can t go back p
  • 在ios中的谷歌地图上添加多个图钉

    我想在加载谷歌地图时在谷歌地图上添加多个图钉 我有附近位置的纬度和经度值的列表 我怎样才能用图钉在地图上显示所有这些位置 我正在使用适用于 iOS 的 Google SDK 我正在使用以下代码 但它对我不起作用 NSMutableArray
  • 如何独立管理和重新加载多个 QuickFIX/J 会话?

    我可以在一个 QuickFIX J 设置文件中配置多个会话 然后使用一个SocketInitiator 但我希望能够修改一个或多个会话的配置 然后仅重新启动这些会话而不影响任何其他会话 我可以通过拥有多个设置文件并使用一个来做到这一点Soc
  • 自定义 TensorFlow 指标:给定假阳性率下的真阳性率

    我有一个二元分类问题 类别背景 bg 0 信号 sig 1 我正在为此训练神经网络 出于监控目的 我尝试在 Keras 中使用 TensorFlow 后端实现自定义指标 该指标执行以下操作 1 计算我的 NN 输出的阈值 这将导致 X 的误
  • 像 gitolite 这样的程序如何工作?

    我很好奇 gitolite 等程序是如何工作的 特别是它们如何与 SSH 协议交互以提供定制的体验 有人可以提供一个例子来说明我如何完成类似以下的事情以及我可以在哪里了解有关该主题的更多信息吗 ssh email protected PTY
  • 准备好的陈述有简写吗?

    最近我开始使用准备好的语句 但是 我觉得我的代码变得有点过于混乱 包含所有临时变量和仅进行单个查询所需的额外行 到目前为止 我的代码如下所示 stmt conn gt prepare SELECT FROM locations WHERE
  • 无需本地信任库的客户端证书身份验证

    好吧 一开始这可能听起来很奇怪 所以请耐心听我说 我需要解决的问题是这样的 我需要以某种方式在 Spring Boot 应用程序中启用客户端身份验证 允许客户端自己创建证书 without服务器需要使用服务器私钥对 CSR 进行签名 我怎样
  • 防止任务管理器中的进程被关闭

    我正在开发一个小程序来提高工作效率 它应该在预设的分钟数后断开用户与互联网的连接或关闭您的计算机 不应使用任务管理器关闭该程序 我可以编译该程序并运行它 但我可以使用任务管理器关闭它 我的灵感来自于这一页 include
  • 如何用 sed、awk 等 shell 命令的输出替换子字符串?

    我想用sed或任何命令行工具 用 shell 命令的输出替换部分行 例如 通过调用将 linux 纪元替换为人类可读的时间戳date 通过调用内部解码器 将特定协议数据包的十六进制转储替换为其解码后的对应数据包 sed似乎最合适 因为它也允
  • Div 在 IE8 中不会浮动

    这将是主要标记 div class mancha div class logo div div class espacio div class eltitular HEADER div div class lacarta LEFT CONT
  • 将随机森林预测作为列添加到测试文件中

    我在 python 中工作pandas in a Jupyter笔记本 我在其中为泰坦尼克号数据集创建了一个随机森林模型 https www kaggle com c titanic data 我读入测试和训练数据 然后清理它并添加新列 两
  • 使用node/js/MySQL工作台将变量传递给查询字符串

    问题 将变量传递到插入语句时 我在数据库中收到空插入 变量有名字 姓氏 电子邮件 密码 我所知道的 我知道我正在获取用户输入表单数据 我正在安慰它们在插入语句之前存储的变量 该语句起作用并将表单数据打印到控制台 当表单在网页上提交时 它存储
  • C# 中两个进程之间的同步。

    有什么办法可以让我们同步两个独立的进程吗 就像如果他们共享资源一样 我想同步它们 我正在使用 C 你可以使用 Mutex 类 请参阅此处的文档 http msdn microsoft com en us library system thr
  • 如何制作库存物品标签 (IN619200) 为收到的每件物品打印一个标签?

    开箱即用Acumatica Inventory Item Label报告 IN619200 旨在仅当项目序列化时才在收据上打印该行项目的多个标签 我们将修改报告 允许用户选择收据编号 并让系统根据每件商品收到的数量生成标签数量 无论它们是否
  • 在 jPanel 周围拖动/移动形状

    昨天我问了一个关于如何绘制边界框以在内部容纳形状的问题如何拖放所选形状 第一个问题就解决了 但我在移动形状时遇到了一些麻烦 是否有任何特定的转换可以在 jPanel 周围移动形状 我有这个代码 public boolean drag Mou
  • Qt 5.2.0 缺少相机服务

    我有一个罗技高清网络摄像头 C270 我想编写一个简单的网络摄像头应用程序 因此我尝试编译 Qt 摄像头示例 Qt Qt5 2 0 5 2 0 msvc 2010 opengl examples multimediawidgets came
  • 如何在sql server中使用like运算符选择匹配百分比高于其他记录的记录?

    我有一组记录需要使用条件进行搜索 但标准返回我多行 因此 我需要具有最大标准匹配百分比的前 2 条记录 我研究了模糊逻辑 但发现对于如此简单的问题来说它太复杂了 我有如下场景 SELECT DISTINCT FirstName LastNa
  • 根据深色或浅色模式更改样式

    我想在我的 Vue 应用程序上有一个深色和浅色主题 我可以创造dark scss文件并更改类样式和使用 important属性来覆盖组件中定义的样式 或者我可以使用props在我的组件中并更改 classNamev if根据主题 例如将类别
  • Microsoft Bond 架构演变最佳实践

    Microsoft Bond 是否有一些关于架构如何随时间演变的最佳实践 我想确保我们遵循最佳实践 以便我们具有两种方式的兼容性 即允许我们的 Bond 类型将旧版本演变成当前版本 以及向后兼容性允许从较新版本转换回旧版本 我没有在文档中看
  • .net core AsyncLocal 失去了价值

    我使用类似的模式HttpContext访问器 简化版本如下 Console WriteLine SimpleStringHolder StringValue 不应该为空 public class SimpleStringHolder pri