?

Nov 17 2017

C#實現多線程的方式:Task——任務

首頁 » 滲透編程 » C#實現多線程的方式:Task——任務   

C#實現多線程的方式:Task——任務

簡介

  .NET 4包含新名稱空間System.Threading.Tasks,它 包含的類抽象出了線程功能。 在后臺使用ThreadPool。 任務表示應完成的某個單元的工作。 這個單元的工作可以在單獨的線程中運行,也可以以同步方式啟動一個任務,這需要等待主調線程。 使用任務不僅可以獲得一個抽象層,還可以對底層線程進行很多控制。 
  在安排需要完成的工作時,任務提供了非常大的靈活性。 例如,可 以定義連續的工 作—— 在一個任務完成后該執行什么工作。 這可以區分任務成功與否。 另外,還可以在層次結構中安排任務。例如,父任務可以創建新的子任務。 這可以創建一種依賴關系,這樣,取消父任務,也會取消其子任務。

啟動任務

  要啟動任務,可 以使用 TaskFactory類 或 Task類 的構造函數和 Start()方法。Task類的構造函數在創建任務上提供的靈活性較大。 
  在啟動任務時,會創建Task類 的一個實例,利用Action或Action<object>委托不帶參數或帶一個object參數 ,可以指定應運行的代碼,這類似于Thread類 。下面定義了一個無參數的方法。 在實現代碼中,把任務的ID寫入控制臺中: 

static void TaskMethod()
{
    Console.WriteLine("running in a task");
    Console.WriteLine("Task id: {0}",Task.CurrentId);
}

  在上面的代碼中,可 以看到啟動新任務的不同方式。第一種方式 使用實例化TaskFactory類 ,在其中把 TaskMedlod()方 法傳遞給StartNew()方法,就會立即啟動任務。 第二種方式使用 Task類的構造函數。 實例化 Task對象時,任務不會立即運行,而是指定 Created狀態。接著調用 Task類的Start()方法,來啟動任務。 使用Task類 時,除了調用 Start()方法,還可以調用RunSynchronously()方法。這樣,任務也會啟動,但在調用者的當前線程中它正在運行,調用者需要一直等待到該任務結束。 默認情況下,任務是異步運行的。 

復制代碼
//using task factory TaskFactory tf = new TaskFactory();
    Task t1 = tf.StartNew(TaskMethod); //using the task factory via a task Task t2 = Task.TaskFactory.StartNew(TaskMethod); //using Task constructor Task t3 = new Task(TaskMethod);
    t3.Start();
復制代碼

  使用Task類的構造函數和TaskFactory類的StartNew()方法時,都可以傳遞TaskCreationOptions枚舉中的值。設置LongRunning選項,可以通知任務調度器,該任務需要較長時間執行,這樣調度器更可能使用新線程。如果該任務應關聯到父任務上,而父任務取消了,則該任務也應取消,此時應設置 AuachToParent選項。PreferFairness的值表示,調度器應提取出已在等待的第一個任務。 如果一個任務在另一個任務內部創建,這就不是默認情況 。如果任務使用子任務創建了其他工作,子任務就優先于其他任務。 它們不會排在線程池隊列中的最后。 如果這些任務應以公平的方式與所有其他任務一起處理,就設置該選項為PreferFairness。 

Task t4 = new Task(TaskMethod, TaskCreationOptions.PreferFairness);
t4.Start();

連續任務

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

復制代碼
static void DoOnFirst()
{
    Console.WriteLine("doing some task {0}",Task.CurrentId);
    Thread.Sleep(3000);
} static void DoOnSecond(Task t)
{
    Console.WriteLine("task {0} finished", t.Id);
    Console.WriteLine("this task id {0}", Task.CurrentId);
    Console.WriteLine("do some cleanup");
    Thread.Sleep(3000);
}
復制代碼

   連續任務通過在任務上調用ContinueWith()方法來定義。也可以使用TaskFactory類來定義。t1.ContinueWith(DoOnSecond)方 法表示,調用DoOnSecond()方法的新任務應在任務t1結束時立即啟動。在一個任務結束時,可以啟動多個任務,連續任務也可以有另一個連續任務,如下面的例子所示:

Task t1 = new Task(DoOnFirst);
Task t2 = t1.ContinueWith(DoOnSecond);
Task t3 = t1.ContinueWith(DoOnSecond);
Task t4 = t2.ContinueWith(DoOnSecond);

 

   無論前一個任務是如何結束的,前 面的連續任務總是在前一個任務結束時啟動。 使用TaskContinuationOptions枚舉中的值,可以指定,連續任務只有在起始任務(或失敗)結束時啟動。一些可能的值是OnlyOnFaulted、 NotOnFaulted、 OnlyOnCanceled、 NotOnCanceled和OnlyOnRanToCompletion。 

Task t5 = t1.ContinueWith(DoOnError, TaskContinuationOptions.OnlyOnFaulted);

任務層次結構

  利用任務連續性,可 以在一個任務結束后啟動另一個任務。 任務也可以構成一個層次結構。 一個任務啟動一個新任務時,就啟動了一個父/子層次結構。 
  下面的代碼段在父任務內部新建一個任務。 創建子任務的代碼與創建父任務的代碼相同,唯一的區別是這個任務從另一個任務內部創建。 

	
  • 復制代碼
    static void ParentAndChild()
    { var parent = new Task(ParentTask);
        parent.Start();
        Thread.Sleep(2000);
        Console.WriteLine(parent.Status);
        Thread.Sleep(4000);
        Console.WriteLine(parent.Status);
    } static void ParentTask()
    {
        Console.WriteLine("task id {0}", Task.CurrentId); var child = new Task(ChildTask);
        child.Start();
        Thread.Sleep(1000);
        Console.WriteLine("parent started child");
    } static void ChildTask()
    {
        Console.WriteLine("child");
        Thread.Sleep(5000);
        Console.WriteLine("child finished");
    }
    復制代碼

  如果父任務在子任務之前結束,父任務的狀態就顯示為WaitingForChildrenToComplete。 只要子任務也結束時,父任務的狀態就變成RanToCompletion。 當然,如 果父任務用TaskCreationOptions枚舉中的 DetachedFromParent創建子任務時,這就無效。

任務的結果

  任務結束時,它可以把一些有用的狀態信息寫到共享對象中。這個共享對象必須是線程安全的。另一個選項是使用返回某個結果的任務。使用 Task類 的泛型版本,就可以定義返回某個結果的任務的返回類型。 
  為了返回某個結果任務調用的方法可以聲明為帶任意返回類型。示例方法TaskWithResult()利用一個元組返回兩個int值。 該方法的輸入可以是void或object類型,如下所示: 

復制代碼
static Tuple<int, int> TaskWithResult(object division)
{
    Tuple<int, int> div =(Tuple<int, int>)division; int result = div.Item1/div.Item2; int reminder = div.Item1%div.Item2;
    Console.WriteLine("task creates a result..."); return Tuple.Create<int, int>(result, reminder);
}
復制代碼

  定義一個調用 StartWithResult()方法的任務時,要使用泛型類Task<Tresult>。 泛型參數定義了返回類型。通過構造函數,把這個方法傳遞給Func委 托,第二個參數定義了輸入值。 因為這個任務在object參數中需要兩個輸入值,所以還創建了一個元組。 接著啟動該任務。 Task實例t1的Result屬性被禁用,并一直等到該任務完成。任務完成后,Result屬性包含任務的結果。 

var t1 = new Task<Tuple<int, int>>(TaskWithResult, Tuple.Create<int, int>(8, 3));
t1.Start();
Console.WriteLine(t1.Result);
t1.Wait();
Console.WriteLine("result from task: {0} {1}",t1.Result.Item1, t1.Result.Item2);

  備注:上例中,Task<Tresult>構造函數調用了TaskFactory.StartNew 方法的 (Func<Object, TResult>, Object)重載。 
  function 
    類型:System.Func<Object, TResult> 
    一個函數委托,可返回能夠通過任務獲得的將來結果。

  state 
    類型:System.Object 
    包含 function 委托所用數據的對象。

  因此我們可以知道,為什么在實例化t1的時候,為什么要創建一個新的Tuple對象了。

轉載來源:http://blog.csdn.net/honantic/article/details/46790707

如果您喜歡本博客,歡迎點擊圖片定訂閱到郵箱填寫您的郵件地址,訂閱我們的精彩內容:

正文部分到此結束

文章標簽:這篇文章木有標簽

版權聲明:若無特殊注明,本文皆為( mOon )原創,轉載請保留文章出處。

也許喜歡: «Masscan及Nmap實現對阿里云ECS的外網端口監控 | 國產ImXSS工具開源發布(附設計文檔)»

你腫么看?

你還可以輸入 250/250 個字

? 微笑 大笑 拽 大哭 親親 流汗 噴血 奸笑 囧 不爽 暈 示愛 害羞 吃驚 驚嘆 愛你 嚇死了 呵呵

評論信息框

這篇文章還沒有收到評論,趕緊來搶沙發吧~

?
?
河北11选5开奖