简介
ThreadLocal 用于在多线程环境中创建线程局部变量,可以让每个线程独立地访问自己的变量副本,互不影响。
而 AsyncLocal 是 ThreadLocal 的异步版本,专门用于异步编程场景,在异步操作中它可以正确处理上下文切换。
ThreadLocal
ThreadLocal<string> ThreadName = new ThreadLocal<string>(() =>
{return "Thread" + Thread.CurrentThread.ManagedThreadId;
});// Action that prints out ThreadName for the current thread
Action action = () =>
{// If ThreadName.IsValueCreated is true, it means that we are not the// first action to run on this thread.bool repeat = ThreadName.IsValueCreated;Console.WriteLine("ThreadName = {0} {1}", ThreadName.Value, repeat ? "(repeat)" : "");
};// 启动八个线程,在4核及一下的电脑上,一些线程名会重复
Parallel.Invoke(action, action, action, action, action, action, action, action);//释放对象
ThreadName.Dispose();
private static ThreadLocal<WebContext> threadLocal = new ThreadLocal<WebContext>(() =>
{var ctx = new WebContext();Console.WriteLine($"创建WebContext");return ctx;
});Console.WriteLine($"主线程: {Thread.CurrentThread.ManagedThreadId}");
//模拟5个HTTP请求
for (var i = 0; i < 5; i++)
{var index = i;Task.Factory.StartNew(() =>{var ctx = threadLocal.Value;ctx.Name = "请求" + index;ctx.Id = index;Console.WriteLine($"请求结束:{index} ctx.Name={ctx.Name} ctx.Id={ctx.Id}");});
}
可以看到,不同的线程值是不同的
AsyncLocal
//父上下文
public static async Task Async()
{asyncLocal.Value = new WebContext{Id = 0,Name = "父"};Console.WriteLine("父:设定ctx:" + asyncLocal.Value);await Async1();Console.WriteLine("父:结束时ctx:" + asyncLocal.Value);}//子上下文
public static async Task Async1()
{Console.WriteLine(" 子读取到ctx:" + asyncLocal.Value);await Async1_1();Console.WriteLine(" 经过孙处理后再读取ctx:" + asyncLocal.Value);asyncLocal.Value = new WebContext{Name = "子",Id = 1,};Console.WriteLine(" 子改动ctx为:" + asyncLocal.Value);await Async1_1();Console.WriteLine(" 经过孙处理后再读取ctx:" + asyncLocal.Value);
}//孙上下文
public static async Task Async1_1()
{Console.WriteLine(" 孙读取到ctx:" + asyncLocal.Value);asyncLocal.Value = new WebContext{Name = "孙",Id = 2,};Console.WriteLine(" 孙改动ctx为:" + 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
值仅向下流动(更深入地进入异步调用堆栈),并且不会将更改向上传播到调用方。
//父上下文
public static async Task Async()
{threadLocal.Value = new WebContext{Id = 0,Name = "父"};Console.WriteLine("父:设定ctx:" + threadLocal.Value);await Async1();Console.WriteLine("父:结束时ctx:" + threadLocal.Value);}//子上下文
public static async Task Async1()
{Console.WriteLine(" 子读取到ctx:" + threadLocal.Value);await Async1_1();Console.WriteLine(" 经过孙处理后再读取ctx:" + threadLocal.Value);threadLocal.Value = new WebContext{Name = "子",Id = 1,};Console.WriteLine(" 子改动ctx为:" + threadLocal.Value);await Async1_1();Console.WriteLine(" 经过孙处理后再读取ctx:" + threadLocal.Value);
}//孙上下文
public static async Task Async1_1()
{Console.WriteLine(" 孙读取到ctx:" + threadLocal.Value);threadLocal.Value = new WebContext{Name = "孙",Id = 2,};Console.WriteLine(" 孙改动ctx为:" + threadLocal.Value);
}class WebContext
{public string Name { get; set; }public int Id { get; set; }public override string ToString(){return $"Name={Name},Id={Id}";}
}