国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

[C#]async和await刨根問底

2019-11-17 02:18:16
字體:
來源:轉載
供稿:網友

[C#]async和await刨根問底

上一篇隨筆留下了幾個問題沒能解決:· 調用IAsyncStateMachine.MoveNext方法的線程何時發起的?· lambda的執行為何先于MoveNext方法?· 后執行的MoveNext方法做了些什么事情?

那么今天就來嘗試解決它們吧~PS: 本文中部分代碼來自上一篇隨筆,具體來源可參考注釋中的章節標題

一、哪里來的線程?

通過上一篇隨筆的調查我們知道了,async標記的方法的方法體會被編譯到一個內部結構體的MoveNext方法中,并且也找到了MoveNext的調用者,再且也證實了有兩個調用者是來自于主線程之外的同一個工作線程。可是這一個線程是何時發起的呢?上一次調查時沒能找到答案,這一次就繼續從MoveNext方法開始,先找找看Task相關的操作有哪些。

 1 // 三、理解await 2 bool '<>t__doFinallyBodies'; 3 Exception '<>t__ex'; 4 int CS$0$0000; 5 TaskAwaiter<string> CS$0$0001; 6 TaskAwaiter<string> CS$0$0002; 7  8 try 9 {10     '<>t__doFinallyBodies' = true;11     CS$0$0000 = this.'<>1__state';12     if (CS$0$0000 != 0)13     {14         CS$0$0001 = this.'<>4__this'.GetHere().GetAwaiter();15         if (!CS$0$0001.IsCompleted)16         {17             this.'<>1__state' = 0;18             this.'<>u__$awaiter1' = CS$0$0001;19             this.'<>t__builder'.AwaitUnsafeOnCompleted(ref CS$0$0001, ref this);20             '<>t__doFinallyBodies' = false;21             return;22         }23     }24     else25     {26         CS$0$0001 = this.'<>u__$awaiter1';27         this.'<>u__$awaiter1' = CS$0$0002;28         this.'<>1__state' = -1;29     }30 31     Console.WriteLine(CS$0$0001.GetResult());32 }

注意到14行的GetHere方法返回了一個Task<string>,隨后的GetAwaiter返回的是TaskAwaiter<string>。不過這兩個Get方法都沒有做什么特別的處理,那么就看看接下來是誰使用了TaskAwaiter<string>實例。于是就來看看19行的AsyncVoidMethodBuilder.AwaitUnsafeOnCompleted里面做了些什么吧。

 1 // System.Runtime.CompilerServices.AsyncVoidMethodBuilder 2 [__DynamicallyInvokable, SecuritySafeCritical] 3 public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>( 4     ref TAwaiter awaiter, ref TStateMachine stateMachine) 5     where TAwaiter : ICriticalNotifyCompletion 6     where TStateMachine : IAsyncStateMachine 7 { 8     try 9     {10         Action completionAction = this.m_coreState11             .GetCompletionAction<AsyncVoidMethodBuilder, TStateMachine>(ref this, ref stateMachine);12         awaiter.UnsafeOnCompleted(completionAction);13     }14     catch (Exception exception)15     {16         AsyncMethodBuilderCore.ThrowAsync(exception, null);17     }18 }

這里主要做了兩件事:一是創建了一個Action,MoveNext方法的信息已經隨著stateMachine被封裝進去了。二是把上面這個Action交給Awaiter,讓它在await的操作完成后執行這個Action。

先來看看Action的構建細節吧:

 1 // System.Runtime.CompilerServices.AsyncMethodBuilderCore 2 [SecuritySafeCritical] 3 internal Action GetCompletionAction<TMethodBuilder, TStateMachine>(ref TMethodBuilder builder, ref TStateMachine stateMachine) 4     where TMethodBuilder : IAsyncMethodBuilder 5     where TStateMachine : IAsyncStateMachine 6 { 7     Debugger.NotifyOfCrossThreadDependency(); 8     ExecutionContext executionContext = ExecutionContext.FastCapture(); 9     Action action;10     AsyncMethodBuilderCore.MoveNextRunner moveNextRunner;11     if (executionContext != null && executionContext.IsPReAllocatedDefault)12     {13         action = this.m_defaultContextAction;14         if (action != null)15         {16             return action;17         }18         moveNextRunner = new AsyncMethodBuilderCore.MoveNextRunner(executionContext);19         action = new Action(moveNextRunner.Run);20         if (AsyncCausalityTracer.LoggingOn)21         {22             action = (this.m_defaultContextAction = this.OutputAsyncCausalityEvents<TMethodBuilder>(ref builder, action));23         }24         else25         {26             this.m_defaultContextAction = action;27         }28     }29     else30     {31         moveNextRunner = new AsyncMethodBuilderCore.MoveNextRunner(executionContext);32         action = new Action(moveNextRunner.Run);33         if (AsyncCausalityTracer.LoggingOn)34         {35             action = this.OutputAsyncCausalityEvents<TMethodBuilder>(ref builder, action);36         }37     }38     if (this.m_stateMachine == null)39     {40         builder.PreBoxInitialization<TStateMachine>(ref stateMachine);41         this.m_stateMachine = stateMachine;42         this.m_stateMachine.SetStateMachine(this.m_stateMachine);43     }44     moveNextRunner.m_stateMachine = this.m_stateMachine;45     return action;46 }

這段的分支有點多,行號上的標記是我DEBUG時經過的分支。可以看到,這個方法里面出現了MoveNext方法的調用者MoveNextRunner,它的Run方法被封裝到了返回的Action里。也就是說,只要這個Action被執行,就會進入Run方法,而Run方法里面有兩條分支,簡單來說就是:1.直接調用MoveNext2.通過InvokeMoveNext調用MoveNext

第40行的賦值不影響Action中的Run,只是在頭尾追加了狀態記錄的操作。接下來就趕緊找一找執行這個Action的地方吧!深入UnsafeOnCompleted方法,最終可以找到如下的方法,第一個參數就是要跟蹤的對象:

 1 // System.Threading.Tasks.Task 2 [SecurityCritical] 3 internal void SetContinuationForAwait( 4     Action continuationAction, 5     bool continueOnCapturedContext, 6     bool flowExecutionContext, 7     ref StackCrawlMark stackMark) 8 { 9     TaskContinuation taskContinuation = null;10     if (continueOnCapturedContext)11     {12         SynchronizationContext currentNoFlow = SynchronizationContext.CurrentNoFlow;13         if (currentNoFlow != null && currentNoFlow.GetType() != typeof(SynchronizationContext))14         {15             taskContinuation = new SynchronizationContextAwaitTaskContinuation(16                 currentNoFlow, continuationAction, flowExecutionContext, ref stackMark);17         }18         else19         {20             TaskScheduler internalCurrent = TaskScheduler.InternalCurrent;21             if (internalCurrent != null && internalCurrent != TaskScheduler.Default)22             {23                 taskContinuation = new TaskSchedulerAwaitTaskContinuation(24                     internalCurrent, continuationAction, flowExecutionContext, ref stackMark);25             }26         }27     }28     if (taskContinuation == null && flowExecutionContext)29     {30         taskContinuation = new AwaitTaskContinuation(continuationAction, true, ref stackMark);31     }32     if (taskContinuation != null)33     {34         if (!this.AddTaskContinuation(taskContinuation, false))35         {36             taskContinuation.Run(this, false);37             return;38         }39     }40     else if (!this.AddTaskContinuation(continuationAction, false))41     {42         AwaitTaskContinuation.UnsafeScheduleAction(continuationAction, this);43     }44 }

同樣的,行號的標記意味著經過的分支。繼續跟進:

 1 // System.Threading.Tasks.AwaitTaskContinuation 2 [SecurityCritical] 3 internal static void UnsafeScheduleAction(Action action, Task task) 4 { 5     AwaitTaskContinuation awaitTaskContinuation = new AwaitTaskContinuation(action, false); 6     TplEtwProvider log = TplEtwProvider.Log; 7     if (log.IsEnabled() && task != null) 8     { 9         awaitTaskContinuation.m_continuationId = Task.NewId();10         log.AwaitTaskContinuationScheduled(11             (task.ExecutingTaskScheduler ?? TaskScheduler.Default).Id,12             task.Id,13             awaitTaskContinuation.m_continuationId);14     }15     ThreadPool.UnsafeQueueCustomWorkItem(awaitTaskContinuation, false);16 }
 1 // System.Threading.ThreadPool 2 [SecurityCritical] 3 internal static void UnsafeQueueCustomWorkItem(IThreadPoolWorkItem workItem, bool forceGlobal) 4 { 5     ThreadPool.EnsureVMInitialized(); 6     try 7     { 8     } 9     finally10     {11         ThreadPoolGlobals.workQueue.Enqueue(workItem, forceGlobal);12     }13 }

這里出現了全局線程池,然而沒有找到MSDN對ThreadPoolGlobals的解釋,這里頭的代碼又實在太多了。。。暫且模擬一下看看:

1 Console.WriteLine("HERE");2 var callback = new WaitCallback(state => Println("From ThreadPool"));3 ThreadPool.QueueUserWorkItem(callback);4 Console.WriteLine("THERE");

QueueUserWorkItem方法內部調用了ThreadPoolGlobals.workQueue.Enqueue,運行起來效果是這樣的:

HERETHEREFrom ThreadPool

再看看線程信息:

Function: CsConsole.Program.Main(), Thread: 0x2E58 主線程Function: CsConsole.Program.Main(), Thread: 0x2E58 主線程Function: CsConsole.Program.Main.AnonymousMethod__6(object), Thread: 0x30EC 工作線程

和async的表現簡直一模一樣是不是~?從調用堆棧也可以看到lambda的執行是源于這個workQueue:

到此為止算是搞定第一個問題了。

二、lambd

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 新宾| 商水县| 四会市| 龙胜| 远安县| 吕梁市| 广灵县| 唐河县| 蒙自县| 新竹县| 丹寨县| 兴安县| 翁牛特旗| 定日县| 阳曲县| 松江区| 平罗县| 宜宾县| 新巴尔虎左旗| 赣榆县| 东丰县| 东乡| 巴塘县| 永修县| 时尚| 射阳县| 运城市| 沙湾县| 古田县| 沅江市| 上林县| 武胜县| 宁夏| 耒阳市| 江永县| 磐安县| 田林县| 隆昌县| 石林| 西丰县| 封丘县|