多線程之任務

来源:http://www.cnblogs.com/afei-24/archive/2017/05/26/6907840.html
-Advertisement-
Play Games

Parallel類(http://www.cnblogs.com/afei-24/p/6904179.html)的並行任務需要結束後才能運行後面的代碼,如果想不等結束後在開始動作,可以使用Task類更好地控制並行動作。 任務表示應完成的某個工作單元。這個工作單元可以在單獨的線程中運行,也可以以同步方 ...


  Parallel類(http://www.cnblogs.com/afei-24/p/6904179.html)的並行任務需要結束後才能運行後面的代碼,如果想不等結束後在開始動作,可以使用Task類更好地控制並行動作。
  任務表示應完成的某個工作單元。這個工作單元可以在單獨的線程中運行,也可以以同步方式啟動一個任務,這需要等待主調線程。使用任務不僅可以獲得一個抽象層,還可以對底層線程進行很多控制。
  任務相對Parallel類提供了非常大的靈活性。例如,可以定義連續的工作——在一個任務完成後該執行什麼工作。這可以根據任務成功與否來分。還可以在層次結構中安排任務。例如,父任務可以創建新的子任務。

一.啟動任務
  要啟動任務,可以使用TaskFactory類或Task類的構造函數和Start()方法。Task類的構造函數在創建任務上靈活性比較大。
  在啟動任務時,會創建Task類的一個實例,利用Action或Action<T>委托(不帶參數或帶一個參數),可以指定應運行的代碼。

  1.使用線程池的任務
  線程池提供了一個後臺線程的池(後面詳細介紹了線程池)。線程池獨自管理線程,根據需要增加或減少線程池中的線程數。線程池中的線程用於實現一些動作,之後仍然返回線程池中。

  下麵介紹創建線程池的任務的四種方法:
  先定義一個要調用使用的方法:

  //避免寫入控制台的操作交叉,這裡使用lock關鍵字同步
        static object taskMethodLock = new object();
        static void TaskMethod(object title)
        {
            lock (taskMethodLock)
            {
                Console.WriteLine(title);
                Console.WriteLine("task id:{0},thread:{1}",Task.CurrentId,Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("is pooled thread:{0}",Thread.CurrentThread.IsThreadPoolThread);
                Console.WriteLine("is background thread:{0}",Thread.CurrentThread.IsBackground);
            }
        }

  (1).使用實例化的TaskFactory類,把TaskMethod方法和TaskMethod方法的參數傳遞給StartNew方法:
    var tf = new TaskFactory();
    Task t1 = tf.StartNew(TaskMethod,"using a task factory");

  (2).使用Task類的靜態屬性Factory來訪問TaskFactory,以調用StartNew()方法。類似第一種,也使用了工廠,但對工廠的控制沒那麼全面。
    Task t2 = Task.Factory.StartNew(TaskMethod,"using factory via a task");

  (3).使用Task的構造函數。實例化Task對象時任務不會執行,只是指定Created狀態。接著調用Start()方法,啟動任務。
    Task t3 = new Task(TaskMethod,"using a task constructor and Start");
    t3.Start();

  (4).直接調用Task類的Run()方法啟動任務。Run()方法沒有傳遞帶參數委托的版本,可以通過傳遞lambda表達式。
    Task t4 = Task.Run(()=> TaskMethod("using Run method"));

 

  static void Main(string[] args)
        {
            var tf = new TaskFactory();
            Task t1 = tf.StartNew(TaskMethod,"using a task factory");

            Task t2 = Task.Factory.StartNew(TaskMethod,"using factory via a task");

            Task t3 = new Task(TaskMethod,"using a task constructor and Start");
            t3.Start();

            Task t4 = Task.Run(()=> TaskMethod("using Run method"));

            Console.ReadKey();
        }

 

  2.同步任務
  任務不一定使用線程池中的線程,也可以使用其它線程。任務也可以同步運行,以相同的線程作為主調線程。
  示例:

      static void RunSyncTask()
            {
                TaskMethod("main thread");
                var t = new Task(TaskMethod,"run sync");
                t.RunSynchronously();
            }

  輸出:
  

  上面代碼先在主線程上直接調用TaskMethod方法,然後在創建的Task上調用。從輸出看到,主線程是一個前臺線程,沒有任務ID,也不是線程池中的線程。調用RunSynchronously方法時,會使用相同的線程,會創建一個任務。

  3.使用單獨線程的任務
  上面將到的任務雖然不是線程池中的線程,但使用的是主線程,不是單獨的,不能實現非同步。
  如果任務的代碼應該長時間運行,就應該使用TaskCreationOptions.LongRunning告訴任務調度器創建一個新的單獨線程,而不是線程池中的線程。這個線程可以不由線程池管理。當線程來自線程池時,任務調度器可以決定等待已經運行的任務完成,然後使用這個線程,而不是線上程池中創建一個新線程。對於長時間運行的線程,任務調度器會立即知道等待它們完成是不明智的做法,會創建一個新的線程。

  示例:

      static void LongRunTask()
            {
                var t = new Task(TaskMethod,"long running",TaskCreationOptions.LongRunning);
                t.Start();
            }

  輸出:
  


二.任務的結果————Future
  任務結束時,可以把一些有用的狀態信息寫入共用對象中。這個共用對象必須是線程安全的。另一個選項是使用返回某個結果的任務。這種任務也叫future,因為它在將來返回一個結果。這需要使用Task類的一個泛型版本。使用這個類可以定義任務返回的結果的類型。
  示例:
  使用泛型類Task<TResult>,TResult是返回類型。通過構造函數,把方法傳遞給Func委托,第二個參數是委托的參數。

      static void Main(string[] args)
            {
                var t = new Task<Tuple<int, int>>(TaskWithResult,Tuple.Create<int,int>(8,3));
                t.Start();
                Console.WriteLine(t.Result);
                t.Wait();
                Console.WriteLine("result from task:{0},{1}", t.Result.Item1, t.Result.Item2);

                Console.ReadKey();
            }

 

  由任務來調用來返回結果的方法可以聲明為任何類型。

static Tuple<int, int> TaskWithResult(object o)
        {
            Tuple<int, int> div = (Tuple<int, int>)o;
            int result = div.Item1 / div.Item2;
            int reminder = div.Item1 % div.Item2;
            Thread.Sleep(10000);
            return Tuple.Create<int, int>(result,reminder);
        }

  這裡使用了元組(http://www.cnblogs.com/afei-24/p/6738155.html).

三.連續的任務
  通過任務,可以指定在任務完成後,應接著運行另一個特定任務。例如,一個使用前一個任務的結果的新任務,如果前一個任務失敗了,這個任務就應執行一些清理工作。
  任務處理程式(前一個任務)或者不帶參數,或者帶一個對象參數,而連續處理程式有一個Task類型的參數,這裡可以訪問前一個任務的相關信息。
  示例:

//一個任務結束時,可以啟動多個任務,連續任務也可以有另一個連續的任務。
        static void Main(string[] args)
        {
            Task t1 = new Task(DoFirst);
            Task t2 = t1.ContinueWith(DoSecond);
            Task t3 = t1.ContinueWith(DoSecond);
            Task t4= t2.ContinueWith(DoSecond);
            t1.Start();
            Console.ReadKey();

        }


        static void DoFirst()
        {
            Console.WriteLine("do some task:{0}",Task.CurrentId);
            Thread.Sleep(3000);
        }
        static void DoSecond(Task t)
        {
            Console.WriteLine("task {0} finished",t.Id);
            Console.WriteLine("this task id:{0}",Task.CurrentId);

        }

 

 

 

  無論前一個任務是如何結束,前面的連續任務總是在前一個任務結束時啟動。使用TaskContinuationOptions枚舉中的值,可以指定,連續任務只有在任務成功或失敗時啟動。
    Task t5 = t1.ContinueWith(DoSecond,TaskContinuationOptions.OnlyOnFaulted);


四.任務的層次結構
  利用任務連續性,可以在一個任務結束後啟動另一個任務。任務也可以構成一個層次結構。在一個任務中啟動一個新的任務時,就啟動了一個父/子層次結構。取消父任務,也會取消子任務。
  創建子任務與創建父任務的代碼相同,唯一區別就就是子任務從另一個任務內部創建。
  示例:

static void Main(string[] args)
        {
            Task t = new Task(ParentTask);
            t.Start();
            Console.ReadKey();

        }

        static void ParentTask()
        {
            Console.WriteLine("parent task id:{0}",Task.CurrentId);
            var child = new Task(ChildTask);
            child.Start();
            Console.WriteLine("parent  create child");
        }

        static void ChildTask()
        {
            Console.WriteLine("child task");
            
        }

  如果父任務在子任務之前結束,父任務的狀態就是WaitingForChildrenToComplete。所有子任務也結束時,父任務的狀態就是RanToCompletion.


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

-Advertisement-
Play Games
更多相關文章
  • 一,工程圖。 二,代碼。 RootViewController.h #import <UIKit/UIKit.h> //加入頭文件 #import "MBProgressHUD.h" @interface RootViewController : UIViewController <MBProgre ...
  • 今晚做android作業,出現錯誤提示:void is an invalid type for the variable, invalid:無效的 variable:變數,在網上找了一下後知道是 方法 沒有弄好,仔細檢查了代碼,是漏了一個右花括弧“}”,加上後,就正常了。 ...
  • 集群信息 角色 IP地址 ServerID 類型 Master 192.168.244.10 1 寫入 Candicate master 192.168.244.20 2 讀 Slave 192.168.244.30 3 讀 Monitor host 192.168.244.40 監控集群組 MHA ...
  • 一、如何查看Redis性能 info命令輸出的數據可以分為10個分類,分別是: server,clients,memory,persistence,stats,replication,cpu,commandstats,cluster,keyspace 為了快速定位並解決性能問題,這裡選擇5個關鍵性的 ...
  • 描述 最近有業務需求需瞭解客戶的伺服器SQLserver 的IO情況,而不僅僅是通過系統計數器 瞭解硬碟的IO情況或者使用CrystalDiskMark或者Trace重播進行壓力測試等 。這時SQL SERVER 2016自帶的SQLIOSIM工具就能很好解決這個需求,工具的預設路徑在D:\Prog ...
  • 一個完整的資料庫部署架構通常由客戶端和伺服器端兩部分組成。客戶端封裝資料庫請求將其發送給伺服器端,伺服器端執行完畢將其及結果返回給伺服器端。 以mysql為例 介紹java應用程式對資料庫的訪問 JDBC意義:應用程式通過調用統一介面實現對任意資料庫的訪問,為我們屏蔽了客戶端與伺服器端交互協議的實現 ...
  • 今天看到了一個新聞,跟大家分享一下,有興趣的可以去嘗試一下。 SQL Server 2017 CTP3於5月23日發佈了,詳細版本號是6.7.55.0。 大家可以去安裝試試。在下載頁面,目前是SQL Server vNext。預計下一個CTP版本會把所有2017的字樣都更新成vNext,計劃是六月份 ...
  • 之前手賤吧,拿濕抹布擦了擦筆記本電腦的自帶鍵盤,然後部分按鍵失靈了。 本想著反正也都是在寢室用的,趁機找藉口買了個機械鍵盤,啪啪啪... 剛開始好好的,後來發現一按shift就會粘貼,百度了下都說是粘滯鍵,可明明設置里是沒開的 換了個外接鍵盤發現也是如此,因此排除了外接鍵盤的問題。 就想著辦法想禁用 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...