.Net AsyncLocal介绍
阅读原文时间:2023年08月16日阅读:1

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

  • AsyncLocal主要是用来在同一个异步控制流内共享对象的,如:一个web请求经过多个 async/await 方法调用后(可能切换了多个线程)依然可以共享同一个对象;

  • AsyncLocal存在层级嵌套的特点,不像ThreadLocal一个线程到底,也就是说AsyncLocal是工作在树形的异步控制流上的;

    class Program
    {
        private static AsyncLocal<WebContext> threadLocal = new AsyncLocal<WebContext>();
        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; }
    }

  • 每个节点都可以有自己的对象;

  • 当子节点没有设置对象时,则访问的是父节点的对象;

  • 当子节点设置了对象时,则访问自己设置的对象;

  • 父节点无法访问子节点设置的对象;

    class Program
    {
        private static AsyncLocal<WebContext> asyncLocal = new AsyncLocal<WebContext>();
        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}";
    }
    }

  • 传递状态数据:在异步操作中,例如异步方法或任务链中,我们可能需要共享某些状态数据。使用AsyncLocal,我们可以在异步操作之间传递这些状态数据,而不必显式地传递参数。

  • 上下文相关信息:有时候,我们可能需要跨异步方法或任务访问一些上下文相关的信息,例如用户身份验证信息、语言设置等。使用AsyncLocal,我们可以在整个异步调用栈中访问这些信息,而不必在每个方法中传递它们作为参数。

    //同一个web请求获取 商户上下文数据都是一样的,而且不会影响另外一个web请求
    public class CurrentContext
    {
        /// <summary>
        /// 商户
        /// </summary>
        private static readonly AsyncLocal<CurrentUser> CurrentUser = new AsyncLocal<CurrentUser>();
    public static void SetCurrentData(CurrentUser currentUser)
    {
        CurrentUser.Value = currentUser;
    }
    
    public static CurrentUser GetCurrentData()
    {
        return CurrentUser.Value??new CurrentUser();
    }
    }

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器