• .Net AsyncLocal介绍


    AsyncLocal的基本概念

    AsyncLocal是一个在异步环境中存储和传递状态的类型。它允许你在线程或任务之间共享数据,而不会受到异步上下文切换的影响。

    每一个异步的AsyncLocal的数据都是独立的

    • AsyncLocal主要是用来在同一个异步控制流内共享对象的,如:一个web请求经过多个 async/await 方法调用后(可能切换了多个线程)依然可以共享同一个对象
    • AsyncLocal存在层级嵌套的特点,不像ThreadLocal一个线程到底,也就是说AsyncLocal是工作在树形的异步控制流上的;
        class Program
        {
            private static AsyncLocal threadLocal = new AsyncLocal();
            static void Main(string[] args)
            {
                //模拟5个HTTP请求
                for (var i = 0; i < 5; i++)
                {
                    var index = i;
                    Task.Factory.StartNew(async () =>
                    {
                        var ctx = threadLocal.Value = new WebContext();
                        ctx.Name = "请求" + index;
                        ctx.Id = index;
                        Console.WriteLine($"Delay前 线程ID:{Thread.CurrentThread.ManagedThreadId} ctx.Name={ctx.Name} ctx.Id={ctx.Id}");
                        await Task.Delay(new Random().Next(1000, 2000));
                        Console.WriteLine($"Delay后 线程ID:{Thread.CurrentThread.ManagedThreadId} ctx.Name={ctx.Name} ctx.Id={ctx.Id}");
                    });
                }
                Console.Read();
            }
        }
    
        class WebContext
        {
            public string Name { get; set; }
            public int Id { get; set; }
        }
    

    image

    AsyncLocal在树形异步控制流上流动的特点:

    • 每个节点都可以有自己的对象;
    • 当子节点没有设置对象时,则访问的是父节点的对象;
    • 当子节点设置了对象时,则访问自己设置的对象;
    • 父节点无法访问子节点设置的对象;
        class Program
        {
            private static AsyncLocal asyncLocal = new AsyncLocal();
            static async Task Main(string[] args)
            {
                await Async();
                Console.Read();
            }
    
            //父上下文
            public static async Task Async()
            {
                asyncLocal.Value = new WebContext
                {
                    Id = 0,
                    Name = "父"
                };
                Console.WriteLine("父:" + asyncLocal.Value);
                await Async1();
                Console.WriteLine("父:" + asyncLocal.Value);
    
            }
    
            //子上下文
            public static async Task Async1()
            {
                Console.WriteLine("子子:" + asyncLocal.Value);
                asyncLocal.Value = new WebContext
                {
                    Name = "子",
                    Id = 1,
                };
                Console.WriteLine("子子:修改后");
                Console.WriteLine("子子:" + asyncLocal.Value);
            }
    
     
        }
    
        class WebContext
        {
            public string Name { get; set; }
            public int Id { get; set; }
    
            public override string ToString()
            {
                return $"Name={Name},Id={Id}";
            }
        }
    

    image

    AsyncLocal的使用场景

    • 传递状态数据:在异步操作中,例如异步方法或任务链中,我们可能需要共享某些状态数据。使用AsyncLocal,我们可以在异步操作之间传递这些状态数据,而不必显式地传递参数。
    • 上下文相关信息:有时候,我们可能需要跨异步方法或任务访问一些上下文相关的信息,例如用户身份验证信息、语言设置等。使用AsyncLocal,我们可以在整个异步调用栈中访问这些信息,而不必在每个方法中传递它们作为参数。
        //同一个web请求获取 商户上下文数据都是一样的,而且不会影响另外一个web请求
        public class CurrentContext
        {
            /// 
            /// 商户
            /// 
            private static readonly AsyncLocal CurrentUser = new AsyncLocal();
    
            public static void SetCurrentData(CurrentUser currentUser)
            {
                CurrentUser.Value = currentUser;
            }
    
            public static CurrentUser GetCurrentData()
            {
                return CurrentUser.Value??new CurrentUser();
            }
        }
    
  • 相关阅读:
    【勇敢饭饭,不怕刷题之链表】两个链表的操作
    springboot(ssm 经方药食两用服务平台 Java(code&LW)
    TCP与UDP协议详解!!!
    数据湖:分布式开源处理引擎Spark
    MySQL事务特性原理
    图解Redis 06 | Hash数据类型的原理及应用场景
    Helm实战案例二:在Kubernetes(k8s)上使用helm安装部署日志管理系统EFK
    阿里云申请免费SSL证书的两种验证方式及配置服务器Tomcat升级HTTPS协议
    Understanding Model Parameters in Machine Learning
    音视频服务架构演进
  • 原文地址:https://www.cnblogs.com/lgxlsm/p/17615799.html