C# Task 源代碼閱讀(1)

来源:http://www.cnblogs.com/enuo/archive/2017/04/05/6668941.html
-Advertisement-
Play Games

平時我們開發中,經常使用Task,後續的.net版本種很多都和Task有關,比如asyn,await有了Task 我們很少就去關註Thread 了。Task 給我們帶來了很多的便利之處。是我們更少的去關註執行的歷程,更多的去關註邏輯。但是有些時候,有些應用。又不得不考慮task 的運行狀況,比如這個 ...


平時我們開發中,經常使用Task,後續的.net版本種很多都和Task有關,比如asyn,await有了Task 我們很少就去關註Thread 了。Task 給我們帶來了很多的便利之處。是我們更少的去關註執行的歷程,更多的去關註邏輯。但是有些時候,有些應用。又不得不考慮task 的運行狀況,比如這個任務成功與否,是否發生異常。經常聽別人說到task 是線上程池執行的,那我們今天就來看看task 到底在做什麼了,他執行的時候又做些哪些工作。

大家可以從這裡可以看到Task 的源代碼,也可以從reference code 直接download 下來。

我們先來看這段代碼

public class Task : IThreadPoolWorkItem, IAsyncResult, IDisposable
    {
        [ThreadStatic]
        internal static Task t_currentTask;  // The currently executing task.
        [ThreadStatic]
        private static StackGuard t_stackGuard;  // The stack guard object for this thread

        internal static int s_taskIdCounter; //static counter used to generate unique task IDs
        private readonly static TaskFactory s_factory = new TaskFactory();

        private volatile int m_taskId; // this task's unique ID. initialized only if it is ever requested

        internal object m_action;    // The body of the task.  Might be Action<object>, Action<TState> or Action.  Or possibly a Func.
        // If m_action is set to null it will indicate that we operate in the
        // "externally triggered completion" mode, which is exclusively meant 
        // for the signalling Task<TResult> (aka. promise). In this mode,
        // we don't call InnerInvoke() in response to a Wait(), but simply wait on
        // the completion event which will be set when the Future class calls Finish().
        // But the event would now be signalled if Cancel() is called
}

先看Task 類繼承的介面,IThreadPoolItem 這個和線程池相關,IAsyncResult這個和非同步執行的回掉相關,這裡我不在過多說這個,

接著我們看到有個欄位t_currentTask ,而且是static 的,指向本身的task。大家不知道會不會有疑問,為什麼這樣設計呢,其實這樣的設計在.net很多地方都有,比如HttpContext等等,特點基本都會有個Current。這種有點類似單例模式,但是開始已經初始化好,還有個更多的有點你可以隨時替換,註入你自己的定義的東西。把他當作單例來用也是完全ok。註意了這裡的訪問修飾符是internal static。

接著t_stackGuard,s_taskIdCounter 顧名思義不在過多介紹。

下麵就是s_factory 註意他是static 和訪問修飾符,當然我如果用工廠模式,一般很少會把當前的工廠放在類內部來使用。哪天我要給我生產出的成品當然得這麼做了。

接著一個比較重要的欄位m_action ,執行體。大家是否記得在彙編里是如何執行所謂函數的,push a push b call xxxx。a,b 分別是參數,xxxx 為跳轉地址 執行代碼,參數的傳遞一般是通過stack 來傳遞。在net 這裡直接放成object ,而且註釋寫的很清楚無非是那些委托。但是對一個函數來說,他的執行體就是call 的地址。

接著我們看下麵的欄位

        internal object m_stateObject; // A state object that can be optionally supplied, passed to action.
        internal TaskScheduler m_taskScheduler; // The task scheduler this task runs under. 

        internal readonly Task m_parent; // A task's parent, or null if parent-less.


        internal volatile int m_stateFlags;

m_stateObject 一猜也大概直到作用。

下麵又是一個執行過程特別重要的欄位m_taskScheduler,在執行過程比較重要。 大家平時windows 的平臺的taskScheduler可能用的比較多,說到taskScheduler,功能也就是在合理時間安排合理的task 執行,實際上就是一個執行管理器。當然我們在sql server 的開發工具也有類似的工作,job 的執行,我們也是要選擇執行計劃的。當然這裡的m_taskScheduler 也許是有本身的意思,都是任務調度器。當然task 預設的taskScheduler與我們剛剛提到的工具功能差距有點大。當然,大家有個印象,就是用來調度task 的。至於怎麼調度,各自有各自的方案。

m_stateFlags 狀態標誌欄位。一個Task 的執行,我當然很想直到他當前的狀態,開始,結束,所以這個也好理解。本身在Thread 種就有很多狀態。

繼續看代碼

   public void Start()
        {
            Start(TaskScheduler.Current);
        }
public void Start(TaskScheduler scheduler)
        {
            // Read the volatile m_stateFlags field once and cache it for subsequent operations
            int flags = m_stateFlags;

            // Need to check this before (m_action == null) because completed tasks will
            // set m_action to null.  We would want to know if this is the reason that m_action == null.
            if (IsCompletedMethod(flags))
            {
                throw new InvalidOperationException(Environment.GetResourceString("Task_Start_TaskCompleted"));
            }

            if (scheduler == null)
            {
                throw new ArgumentNullException("scheduler");
            }

            var options = OptionsMethod(flags);
            if ((options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0)
            {
                throw new InvalidOperationException(Environment.GetResourceString("Task_Start_Promise"));
            }
            if ((options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) != 0)
            {
                throw new InvalidOperationException(Environment.GetResourceString("Task_Start_ContinuationTask"));
            }

            // Make sure that Task only gets started once.  Or else throw an exception.
            if (Interlocked.CompareExchange(ref m_taskScheduler, scheduler, null) != null)
            {
                throw new InvalidOperationException(Environment.GetResourceString("Task_Start_AlreadyStarted"));
            }

            ScheduleAndStart(true);
        }

 

我們平常都會用start方法,他會預設傳入一個TaskScheduler,我們接著看下麵的方法,最後調用的是ScheduleAndStart方法,不管前面的驗證,我們重點看執行流程,要弄清這點,我們必須清楚TaskScheduler.Current

到底是什麼類,他的功能是什麼,如果我們自己去寫TaskScheduler,那又該去寫什麼,完成哪些功能。

我們繼續從reference code 找到TaskScheduler 類。我們先重點追蹤Current ,先不管方法。

 public static TaskScheduler Current 
        {
            get
            {
                TaskScheduler current = InternalCurrent;
                return current ?? TaskScheduler.Default;
            }
        }
 internal static TaskScheduler InternalCurrent
        {
            get
            {
                Task currentTask = Task.InternalCurrent;
                return ( (currentTask != null) 
                    && ((currentTask.CreationOptions & TaskCreationOptions.HideScheduler) == 0)
                    ) ? currentTask.ExecutingTaskScheduler : null;
            }
        }

 

預設我繼續找到default 屬性
public static TaskScheduler Default 
        {
            get
            {
                return s_defaultTaskScheduler;
            }
        }
   private static readonly TaskScheduler s_defaultTaskScheduler = new ThreadPoolTaskScheduler();

 

我們一步一步追蹤,終於找到了ThreadPoolTaskScheduler,這時終於可以task 把threadpool 聯繫起來了。

再看執行
ScheduleAndStart之前,我們看下
  if (Interlocked.CompareExchange(ref m_taskScheduler, scheduler, null) != null)
 這句的寫法,null 判斷再加上對象的賦值。這個我們可以在平時的代碼中加以借用。



 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、屌絲也有春天 "親愛的,在不?" "妹子,你電腦又感覺慢了麽?您以後裝軟體的時候註意點行不,能不能不要裝上7-8個瀏覽器,3-4個殺毒軟體,啥配置的機子你都感覺卡。以後別到處瞎找動作類電影看,網上一般都掛馬騙你們這些小白的,實在想看找我要種子不就行了。" "沒有啦,人家電腦好著呢,您不是做軟體的 ...
  • 如果大家研究一些開源項目,會發現無處不在的DI(Dependency Injection依賴註入)。 本篇文章將會詳細講述如何在MVC中使用Ninject實現DI 文章提綱 場景描述 & 問題引出 第一輪重構 引入Ninject 第二輪重構 總結 場景描述 & 問題引出 DI是一種實現組件解耦的設計 ...
  • 度娘許久,找不到我滿意的答案,於是自己東湊西湊實現一個。 DynamicObject擴展--實現JSON和DynamicObject的序列化與反序列化,親測良好。 看代碼 ...
  • 跨平臺系列彙總:http://www.cnblogs.com/dunitian/p/4822808.html#linux 上次說了安裝VSCode(http://www.cnblogs.com/dunitian/p/6661644.html)和sogou(http://www.cnblogs.com ...
  • 本章內容和大家分享的是Asp.NetCore組件寫法,在netcore中很多東西都以提供組件的方式來使用,比如MVC架構,Session,Cache,資料庫引用等; 這裡我也通過調用驗證碼介面來自定義個組件以此說明如何使用,以及使用時需要註意的場景; Middleware之hello world 對 ...
  • 對於WCF應用來說,傳輸前壓縮請求消息和回覆消息,不但可以降低網路流量,也可以提高網路傳輸的性能 一、消息壓縮方案 二、用於數據壓縮與解壓縮組件 三、用於消息壓縮與解壓的組件 四、用於對請求/回覆消息壓縮和解壓縮的組件 五、將CompressionMessageFormatter用於WCF運行時框架 ...
  • 最近接觸了用c#導出Excel文件的一些操作。 使用NPOI的優勢是,開源,操作靈活,不需要下載OFFICE軟體,速度快,不過聽說,數據量過大的時候,不是很好用,大概那都是幾兆的時候吧,不過目前用於我的需要,基本是夠了。 關於NPOI的基本操作:http://blog.csdn.net/pan_ju ...
  • DevExpress 是一個比較有名的界面控制項套件,提供了一系列優秀的界面控制項。這篇文章將展示如何在擁有源代碼的情況下,對 DevExpress 的程式集進行重新編譯。 系統必備 Windows 7 SP1 以上操作系統 Visual Studio 2010 SP1 .Net Framework 4 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...