iT邦幫忙

2021 iThome 鐵人賽

DAY 9
0
自我挑戰組

從C到JS的同步非同步探索系列 第 9

[Day 9] .Net Task 底層(2)

  • 分享至 

  • xImage
  •  

前言

我們昨天聊到要透過解析 threadPool 檔案中的 FinishContinuations method 來了解 .Net 框架中 threadPool 的樣貌以及使用。而FinishContinuations 會在特定階段被 Task 調用。

資料來源 : https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,dadbf616e42976ee

正文

 internal void FinishContinuations()
{
    // 設定目前執行任務完成, 因為此函數會在 Task 完成其任務時被調用
    object continuationObject = Interlocked.Exchange(ref m_continuationObject, s_taskCompletionSentinel);
    TplEtwProvider.Log.RunningContinuation(Id, continuationObject);

    // 在 WhenAll 提過, 當別的物件要把某個任務放到某個任務後面執行時, 就會將那個任務加入到 連續任務區
		// 當連續任務區為空, 此任務結束。
    if (continuationObject != null)
    {
		// 連續任務區不為空要執行以下這段
        if (AsyncCausalityTracer.LoggingOn)
            AsyncCausalityTracer.TraceSynchronousWorkStart(CausalityTraceLevel.Required, this.Id, CausalitySynchronousWork.CompletionNotification);

        // Skip synchronous execution of continuations if this task's thread was aborted
        bool bCanInlineContinuations = !(((m_stateFlags & TASK_STATE_THREAD_WAS_ABORTED) != 0) ||
                                          (Thread.CurrentThread.ThreadState == ThreadState.AbortRequested) ||
                                          ((m_stateFlags & (int)TaskCreationOptions.RunContinuationsAsynchronously) != 0));

        // 若是連續任務區只有一個 Action 就直接執行或送入排程(這個 method 有點東西, 目前不能細說)
        Action singleAction = continuationObject as Action;
        if (singleAction != null)
        {
            AwaitTaskContinuation.RunOrScheduleAction(singleAction, bCanInlineContinuations, ref t_currentTask);
            LogFinishCompletionNotification();
            return;
        }

        // Handle the single-ITaskCompletionAction case
        ITaskCompletionAction singleTaskCompletionAction = continuationObject as ITaskCompletionAction;
        if (singleTaskCompletionAction != null)
        {
			// 可以接著執行
            if (bCanInlineContinuations)
            {
				// 直接用同一個 Task 接著執行這個任務
                singleTaskCompletionAction.Invoke(this);
            }
            else
            {
				// 不能用同一個 task 接著執行, 把 Task 打包加入 TP
                ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(singleTaskCompletionAction, this), forceGlobal: false);
            }
            LogFinishCompletionNotification();
            return;
        }

        // 此段流程和上一段很像, 略。
        TaskContinuation singleTaskContinuation = continuationObject as TaskContinuation;
        if (singleTaskContinuation != null)
        {
            singleTaskContinuation.Run(this, bCanInlineContinuations);
            LogFinishCompletionNotification();
            return;
        }
				
        // Not a single; attempt to cast as list
        List<object> continuations = continuationObject as List<object>;
				// 連續任務為空
        if (continuations == null)
        {
            LogFinishCompletionNotification();
            return;  // Not a single or a list; just return
        }

        //
        // Begin processing of continuation list
        //

        // 此段是在處理, 連續任務區 有多個任務時的狀況, 略, 明天聊
    }
}

可以發現以下流程

  1. Task 完成其任務
  2. 設定目前執行任務完成
  3. 檢查 連續任務區
  4. 若是只有一個連續任務
    1. 若是可以在同一個 Thread 接著執行就接著執行
    2. 若是不可以在同一個 Thread 就推入 threadPool 給別人執行

此外, 連續任務若有多個任務, 有另一套處理程序。

可以在同一個 Thread 接著執行的評斷標準之後也會聊到。

雖然只有一個連續任務看起來有三種處理的 CASE , 但究其本質都是差不多的。

明天我們針對 ITaskCompletionAction 這個 CASE 往下,

要看

 singleTaskCompletionAction.Invoke(this); 

ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(singleTaskCompletionAction, this), forceGlobal: false);

為何一個可以使原來的 Task 接著執行連續任務, 另一個可以 把 task 送入 TP 給別人執行。

明天進度

今天因為篇幅問題, 沒有聊到 TP , 所以明天就繼續寫, 看能不能把上面那兩個 method 聊完。

明天見!


上一篇
[Day 8] .Net Task 底層(1)
下一篇
[Day 10] .Net Task 底層(3)
系列文
從C到JS的同步非同步探索30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言