Hello World!
Toggle navigation
Home
开发
运维部署
旧博客搬家
About Me
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Archives
Tags
AsyncLocal特性解析
2019-08-09 07:43:05
30
0
0
lion
# 1、跨线程性质 AsyncLocal与方法调用上下文(ExecutionContext)绑定,简单理解就是:相当于局部变量。 ## 实验代码 using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp2 { class Program { static AsyncLocal<string> d = new AsyncLocal<string>(); static Random rd = new Random(); static void Main(string[] args) { Console.WriteLine("Hello World!"); for (int i = 0; i < 10; i++) { Task.Factory.StartNew(TMain);//10个并发 } Console.ReadLine(); } public static async Task TMain() { int scope = rd.Next(0, 10000); //产生一个随机数scope d.Value = scope.ToString(); //赋给AsyncLocal System.Diagnostics.Trace.WriteLine("[" + System.Threading.Thread.CurrentThread.ManagedThreadId + "] set scope:" + scope); //记录scope所在线程 new System.Threading.Thread(Main1).Start(scope); //开新线程,传入scope值, Task.Run(() => { Main2(scope); }); //Task方式跨线程 await Main3(scope); //异步方式跨线程 } public static void Main1(object scope) { System.Threading.Thread.Sleep(rd.Next(1, 10)); //随机休眠 System.Diagnostics.Trace.WriteLine("main1[" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]scope:" + scope + ",d:" + d.Value); } public static async Task Main3(int scope) { await Task.Delay(rd.Next(1, 10)); System.Diagnostics.Trace.WriteLine("main3[" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]scope:" + scope + ",d:" + d.Value); } public static void Main2(int scope) { System.Threading.Thread.Sleep(rd.Next(1, 10)); System.Diagnostics.Trace.WriteLine("main2[" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]scope:" + scope + ",d:" + d.Value); } } } ## 输出结果 [5] set scope:7810 [4] set scope:3704 [6] set scope:2435 [7] set scope:1011 main1[10]scope:2435,d:2435 main3[7]scope:3704,d:3704 main1[8]scope:3704,d:3704 main3[7]scope:2435,d:2435 main2[6]scope:2435,d:2435 main2[4]scope:3704,d:3704 main2[5]scope:7810,d:7810 [4] set scope:3774 [5] set scope:5339 main3[6]scope:1011,d:1011 main2[7]scope:1011,d:1011 [6] set scope:3421 [7] set scope:2080 main1[9]scope:7810,d:7810 main1[11]scope:1011,d:1011 main1[12]scope:3774,d:3774 main2[5]scope:5339,d:5339 main1[13]scope:5339,d:5339 [5] set scope:1308 main2[7]scope:2080,d:2080 main3[6]scope:5339,d:5339 [7] set scope:8773 main1[14]scope:3421,d:3421 main3[4]scope:3421,d:3421 main1[15]scope:2080,d:2080 main2[5]scope:1308,d:1308 main3[4]scope:1308,d:1308 main3[5]scope:7810,d:7810 main2[6]scope:3421,d:3421 main3[4]scope:3774,d:3774 main3[5]scope:2080,d:2080 main3[7]scope:8773,d:8773 main1[16]scope:1308,d:1308 main1[17]scope:8773,d:8773 main2[4]scope:3774,d:3774 main2[6]scope:8773,d:8773 ## 结论 你会发现,d是个静态实例,但无论怎么跨线程,从d.Value取到的值,都跟传进来的实参scope是一致的,就是说,可以替代scope实参的传递,不会产生跨线程问题。 那么,你可以这样理解,d其实只是个取值的方法,调d.Value的时候,实际上从当前调用上下文里存取数据,并不会保存在静态对象本身上。 ## 用处 对于Aop用处比较大,比如想传一些Context的参数,但又不能放进接口定义中。 再具体点: 比如,在mvc里,要从Middleware或Filter中传值给Action。 # 2、作用域 ## 试验代码 static void Main(string[] args) { Console.WriteLine("Hello World!"); TScope().Wait(); Console.ReadLine(); } public static async Task TScope() { int scope = rd.Next(0, 10000); //产生一个随机数scope d.Value = scope.ToString(); //赋给AsyncLocal System.Diagnostics.Trace.WriteLine("TScope[" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]set scope:" + scope + ",d:" + d.Value); await Tscope2(scope); System.Diagnostics.Trace.WriteLine("Tscope[" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]scope:" + scope + ",d:" + d.Value); } public static async Task Tscope2(int pscope) { System.Diagnostics.Trace.WriteLine("Tscope2[" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]pscope:" + pscope + ",d:" + d.Value); int scope = rd.Next(0, 10000); //产生一个随机数scope d.Value = scope.ToString(); //赋给AsyncLocal System.Diagnostics.Trace.WriteLine("Tscope2[" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]pscope:" + pscope + ",set scope:" + scope + ",d:" + d.Value); await Tscope3(scope); System.Diagnostics.Trace.WriteLine("Tscope2[" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]pscope:" + pscope + ",scope:" + scope + ",d:" + d.Value); } public static async Task Tscope3(int pscope) { System.Diagnostics.Trace.WriteLine("Tscope3[" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]pscope:" + pscope + ",d:" + d.Value); int scope = rd.Next(0, 10000); //产生一个随机数scope d.Value = scope.ToString(); //赋给AsyncLocal System.Diagnostics.Trace.WriteLine("Tscope3[" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]pscope:" + pscope + ",set scope:" + scope + ",d:" + d.Value); } ## 输出结果 TScope[1]set scope:2251,d:2251 Tscope2[1]pscope:2251,d:2251 Tscope2[1]pscope:2251,set scope:4812,d:4812 Tscope3[1]pscope:4812,d:4812 Tscope3[1]pscope:4812,set scope:29,d:29 Tscope2[1]pscope:2251,scope:4812,d:4812 Tscope[1]scope:2251,d:2251 ## 结论 对d.Value的赋值,作用域为当前方法,以及子方法,也调是调用链下方,不会返回到上一级方法。 这也跟局部变量(非ref和out类型)相似,局部变量 可以 作为实参往下传,但不能往上传。 (用过python的同学,有没有觉得跟python里变量的作用域一样一样的?)
Pre:
Docker
Next:
GitBook使用
0
likes
30
Weibo
Wechat
Tencent Weibo
QQ Zone
RenRen
目录