.Net多線程編程—任務Task


1 System.Threading.Tasks.Task簡介

一個Task表示一個異步操作,Task的創建和執行是獨立的。

只讀屬性:

返回值

名稱

說明

object

AsyncState

表示在創建任務時傳遞給該任務的狀態數據

TaskCreationOptions

CreationOptions

獲取用於創建此任務的 TaskCreationOptions

 

CurrentId

當前正在執行 Task 的 ID

AggregateException

Exception

獲取導致 AggregateException 提前結束的 Task。如果 Task 成功完成或尚未引發任何異常,則返回 null

TaskFactory

Factory

提供對用於創建 Task 和 Task<TResult> 的工廠方法的訪問

int

Id

獲取此 Task 實例的 ID

bool

IsCanceled

指明此 Task 實例是否由於被取消的原因而已完成執行

bool

IsCompleted

指明此 Task 是否已完成

bool

IsFaulted

指明Task 是否由於未經處理異常的原因而完成

TaskStatus

Status

獲取此任務的 TaskStatus

 

2 Task狀態和生命周期

一個Task實例只會完成其生命周期一次,當Task達到它的3種可能的最終狀態之一時,它就再也回不去之前的狀態了。任務的生命周期從TaskStatus.Created狀態真正開始。

1) 初始狀態

Task實例有三種可能的初始狀態

說明

TaskStatus.Created

該任務已初始化,但尚未被計划。使用Task構造函數創建Task實例時的初始狀態。

TaskStatus.WaitingForActivation

該任務正在等待 .NET Framework 基礎結構在內部將其激活並進行計划。一個任務的初始狀態,這個任務只有當其依賴的任務完成之后才會被調度。

TaskStatus.WaitingToRun

該任務已被計划執行,但尚未開始執行。使用TaskFactory.StartNew創建的任務的初始狀態。

2)中間狀態

Task實例有兩種可能的中間狀態

說明

TaskStatus.Running

該任務正在運行,但尚未完成

TaskStatus.WaitingForChildrenToComplete

該任務已完成執行,正在隱式等待附加的子任務完成

 

3) 最終狀態

Task實例有三種可能的最終狀態

說明

TaskStatus.Canceled

該任務已通過對其自身的 CancellationToken 引發 OperationCanceledException 對取消進行了確認,此時該標記處於已發送信號狀態;或者在該任務開始執行之前,已向該任務的 CancellationToken 發出了信號。Task屬性IsFaulted被設置為true

TaskStatus.Faulted

由於未處理異常的原因而完成的任務。Task屬性IsCanceled被設置為true

TaskStatus.RunToCompletion

已成功完成執行的任務。Task屬性IsCompleted被設置為trueIsFaultedIsCanceled被設置為false

 

3 創建並執行任務

1)public Task StartNew(Action action)

參數:

  action:要異步執行的操作委托

返回值:

  已啟動的 System.Threading.Tasks.Task

異常:

  System.ArgumentNullException:當 action 參數為 null 時引發的異常。

2)public static Task Run(Action action)

參數:

  action:表示在線程池執行的隊列的任務

返回值:

  已啟動的 System.Threading.Tasks.Task

異常:

  System.ArgumentNullException:當 action 參數為 null 時引發的異常。

3)public void Start()

啟動 System.Threading.Tasks.Task,並將它安排到當前的 System.Threading.Tasks.TaskScheduler中執行。

異常:

  System.ObjectDisposedException:已釋放 System.Threading.Tasks.Task 實例。

  System.InvalidOperationExceptionSystem.Threading.Tasks.Task 未處於有效狀態,無法啟動。 它可能已啟動、已執行或已取消,或者可能已經不支持以直接計划的方式創建。

注意:

  僅使用Task的構造器來創建Task的實例並不能啟動任務,還要使用Start才能啟動任務。

4)Task.Factory.StartNewTask.Run

Task.Factory.StartNew重載方法提供更多的參數,可以控制如何計划執行任務以及如何向調試器公開計划任務的機制和控制任務的創建和執行的可選行為。

而Task.Run提供的方法則不具有上述控制機制。

 

4 等待任務完成

1)public void Wait()

等待 System.Threading.Tasks.Task 完成執行過程

異常:

  ObjectDisposedException:Task 對象已被釋放。

  AggregateExceptionSystem.Threading.Tasks.Task 已取消或在 System.Threading.Tasks.Task 的執行期間引發了異常。如果任務已被取消,System.AggregateException將包含其 System.AggregateException.InnerExceptions 集合中的 System.OperationCanceledException

2public static void WaitAll(params Task[] tasks)

參數:

  tasks:要等待的 Task 實例的數組

異常:

  ObjectDisposedException:一個或多個 Task 中的對象 tasks 已被釋放。

  ArgumentNullExceptiontasks 參數為 nulltasks 參數包含 null 元素。

  AggregateException:在至少一個 Task 實例已取消。如果任務已被消, AggregateException 異常包含 OperationCanceledException 中的異常其   AggregateException.InnerExceptions 集合。或在至少一個執行期間引發了異常 Task 實例。

說明:

  主線程會等待作為參數傳入的任務tasks執行結束才會執行下一條語句。

3)public static int WaitAny(params Task[] tasks)

參數:

  tasks:要等待的 Task 實例的數組

異常:

  System.ObjectDisposedExceptionSystem.Threading.Tasks.Task 已被釋放。

  System.ArgumentNullExceptiontasks 參數為 null

  System.ArgumentExceptiontasks 參數包含 null 元素。

 

5 取消任務

使用System.Threading.CancellationToken和System.Threading.CancellationTokenSource中斷Task的執行。

1)System.Threading.CancellationToken

傳播有關應取消操作的通知

屬性:

  public bool IsCancellationRequested { get; }

方法

  public void ThrowIfCancellationRequested();

  如果已請求取消此標記,則引發 System.OperationCanceledException。

異常:

  System.OperationCanceledException:該標記已請求取消。

      System.ObjectDisposedException:關聯的System.Threading.CancellationTokenSource已被釋放。

2) System.Threading.CancellationTokenSource

通知 System.Threading.CancellationToken,告知其應被取消

屬性:

  public CancellationToken Token { get; }:獲取與此 System.Threading.CancellationTokenSource 關聯的 System.Threading.CancellationToken。

異常:

  System.ObjectDisposedException:已釋放標記源。

方法:

  public void Cancel():傳達取消請求。

異常:

  System.ObjectDisposedException: System.Threading.CancellationTokenSource 已被釋放。

  System.AggregateException:聚合異常包含由相關聯的 System.Threading.CancellationToken 上已注冊的回調引發的所有異常。

 

6 任務的返回值

1)Task類型

在第1節中已經介紹了Task

2)Task<TResult>類型

屬性

定義

說明

public static TaskFactory<TResult> Factory { get; }

提供對用於創建 System.Threading.Tasks.Task<TResult> 實例的工廠方法的訪問。

public TResult Result { get; }

獲取此 System.Threading.Tasks.Task<TResult> 的結果值

方法

  public Task ContinueWith(Action<Task<TResult>> continuationAction)

參數:

  continuationAction:在 System.Threading.Tasks.Task<TResult> 完成時要運行的操作。在運行時,委托將作為一個參數傳遞給完成的任務。

異常:

  System.ObjectDisposedException:System.Threading.Tasks.Task<TResult> 已被釋放。

  System.ArgumentNullException:continuationAction 參數為 null。

注意:

  • 該方法的重載方法提供了更多的控制機制。可以傳入CancellationTokenTaskContinuationOptionsTaskScheduler參數。
  • 使用Task.Factory.StartNew方法,如果傳入的委托無返回值,那么方法執行的返回結果類型其實是Task<TResult>,通過Task<TResult>類型的Result 屬性可以查看返回結果。對於串聯的多個任務,若后續的任務要使用上一個任務的結果,那么Task.Factory.StartNew返回值類型必須是Task<TResult>var
  • 返回值可以是自定義類型。

 

7 TaskCreationOptions (枚舉類型)

用途:控制任務創建與執行的行為。

說明

TaskCreationOptions.None

指定應使用默認行為

TaskCreationOptions.PreferFairness

提示 System.Threading.Tasks.TaskScheduler 以一種盡可 能公平的方式安排任務,這意味着較早安排的任務將更可能較早運行,而較晚安排運行的任務將更可能較晚運行

TaskCreationOptions.LongRunning

指定某個任務將是運行時間長、粗粒度的操作。 它會向 System.Threading.Tasks.TaskScheduler 提示,過度訂閱可能是合理的。

TaskCreationOptions.AttachedToParent

指定將任務附加到任務層次結構中的某個父級

TaskCreationOptions.DenyChildAttach

如果嘗試附有子任務到創建的任務,指定 System.InvalidOperationException 將被引發

TaskCreationOptions.HideScheduler

防止環境計划程序被視為已創建任務的當前計划程序。 這意味着像 StartNew 或 ContinueWith 創建任務的執行操作將被視為 System.Threading.Tasks.TaskScheduler.Default當前計划程序

8 任務計划TaskScheduler

功能:擴展任務執行計划,例如自定義任務計划程序來實現性能加速。

屬性:

名稱

說明

Current

當前正在執行的任務關聯的 TaskScheduler

Id

TaskScheduler 的唯一 ID

MaximumConcurrencyLevel

指示此 TaskScheduler 能夠支持的最大並發級別

 

9 串聯多個任務

1public Task ContinueWith(Action<Task> continuationAction);

參數:

  continuationAction:在 System.Threading.Tasks.Task 完成時要運行的操作。 在運行時,委托將作為一個參數傳遞給完成的任務。

異常:

  System.ObjectDisposedException:創建了 cancellationToken System.Threading.CancellationTokenSource 已經被釋放。

  System.ArgumentNullExceptioncontinuationAction 參數為 null

2public Task ContinueWith(Action<Task> continuationAction, TaskContinuationOptions continuationOptions);

參數:

  continuationAction:根據在 continuationOptions 中指定的條件運行的操作。 在運行時,委托將作為一個參數傳遞給完成的任務。

  continuationOptions:用於設置計划延續任務的時間以及延續任務的工作方式的選項。

3TaskContinuationOptions

enum類型,用於設置計划延續任務的時間以及延續任務的工作方式的選項。 這包括條件(如 System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled)和執行選項(如

System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously)。

說明

ContinuationOptions.None

指定應使用默認行為。默認情況下,完成前面的任務之后將安排運行延續任務,而不考慮前面任務的最終 System.Threading.Tasks.TaskStatus

 

ContinuationOptions.LongRunning

指定某個任務將是運行時間長、粗粒度的操作。 它會向 System.Threading.Tasks.TaskScheduler 提示,過度訂閱可能是合理的。

ContinuationOptions.AttachedToParent

指定將任務附加到任務層次結構中的某個父級。

ContinuationOptions.DenyChildAttach

如果嘗試附有子任務到創建的任務,指定 System.InvalidOperationException 將被引發。

ContinuationOptions.HideScheduler

防止環境計划程序被視為已創建任務的當前計划程序。 這意味着像 StartNew ContinueWith 創建任務的執行操作將被視為System.Threading.Tasks.TaskScheduler.Default當前計划程序。

ContinuationOptions.LazyCancellation

在延續取消的情況下,防止延續的完成直到完成先前的任務

ContinuationOptions.NotOnRanToCompletion

指定不應在延續任務前面的任務已完成運行的情況下安排延續任務。 此選項對多任務延續無效

ContinuationOptions.NotOnFaulted

指定不應在延續任務前面的任務引發了未處理異常的情況下安排延續任務。 此選項對多任務延續無效

ContinuationOptions.OnlyOnCanceled

指定只應在延續任務前面的任務已取消的情況下才安排延續任務。 此選項對多任務延續無效

ContinuationOptions.NotOnCanceled

指定不應在延續任務前面的任務已取消的情況下安排延續任務。 此選項對多任務延續無效

ContinuationOptions.OnlyOnFaulted

指定只應在延續任務前面的任務引發了未處理異常的情況下才安排延續任務。 此選項對多任務延續無效

ContinuationOptions.OnlyOnRanToCompletion

指定只應在延續任務前面的任務已完成運行的情況下才安排延續任務。 此選項對多任務延續無效

ContinuationOptions.ExecuteSynchronously

指定應同步執行延續任務。 指定此選項后,延續任務將在導致前面的任務轉換為其最終狀態的相同線程上運行。 如果在創建延續任務時已經完成前面的任務,則延續任務將在創建此延續任務的線程上運行。只應同步執行運行時間非常短的延續任務

ContinuationOptions.PreferFairness

提示 System.Threading.Tasks.TaskScheduler 以一種盡可能公平的方式安排任務,這意味着較早安排的任務將更可能較早運行,而較晚安排運行的任務將更可能較晚運行。

 

注意:

1)可以通過位操作組合使用多個值。

2)使用ContinuationOptions.None意味着不論前面的任務是否被取消,延續任務都會執行。

異常:

  System.ObjectDisposedExceptionSystem.Threading.Tasks.Task 已被釋放。

  System.ArgumentNullExceptioncontinuationAction 參數為 null

  System.ArgumentOutOfRangeExceptioncontinuationOptions 參數為 System.Threading.Tasks.TaskContinuationOptions 指定無效值。

3)子任務(嵌套任務):在父任務的委托中創建的 System.Threading.Tasks.Task 實例。 子任務包括兩種:附加的子任務與分離的子任務

  • 分離的子任務是不依賴於其父級而執行。
  • 附加的子任務是使用 TaskCreationOptions.AttachedToParent 選項創建的,依賴於其父任務而執行。 對父任務使用TaskCreationOptions.DenyChildAttach來阻止子任務附加到父任務。
  • 一個任務可以創建任意數量的附加的子任務和分離的子任務,這僅受系統資源限制。
  • 不提倡創建附加的子任務,這樣會大大增加程序設計的復雜性。

 

10 使用模式

1)創建任務

基本形式:

 1 private void CreatTask()
 2 {
 3     //創建並執行任務
 4     Task task = new Task(() =>
 5     {
 6         //具體操作
 7     });
 8     task.Start();
 9 
10     //創建並將任務加入執行計划,使用StartNew
11     Task.Factory.StartNew(() => {
12         //具體操作
13     });
14 
15     //創建並將任務加入執行計划,使用Run
16     Task.Run(() =>
17     {
18         //具體操作
19     });
20 
21     //安排任務
22     Task.Factory.StartNew(() =>
23     {
24         //具體操作
25     },TaskCreationOptions.PreferFairness);
26 }    

創建附加的子任務:

 1 private void CreateTask_Parent()
 2 {
 3     //附加子任務
 4     var taskParent = Task.Factory.StartNew(() =>
 5     {
 6         //操作......
 7         var child = Task.Factory.StartNew(() =>
 8         {
 9             //具體操作
10         }, TaskCreationOptions.AttachedToParent);
11     });
12     taskParent.Wait();
13 
14 
15     //阻止附加子任務
16     var taskParentZ = Task.Factory.StartNew(() =>
17     {
18         //操作......
19         var child = Task.Factory.StartNew(() =>
20         {
21             //即使設置TaskCreationOptions.AttachedToParent也無法將其附加到父任務
22             //具體操作
23         }, TaskCreationOptions.AttachedToParent);
24     }, TaskCreationOptions.DenyChildAttach);
25     taskParentZ .Wait();
26 }    

2)取消任務

 1 public static void CancelFromExternal_Task()
 2 {
 3     CancellationTokenSource cts = new CancellationTokenSource();
 4 
 5     //其他操作...
 6 
 7     //計算condition
 8     bool condition = ...;
 9     if (condition) cts.Cancel();
10     //或使用Operation2_Task(cts);
11     Operation1_Task(cts);
12     //其他操作...
13 
14 }
15 
16     //1 使用IsCancellationRequested屬性
17     private static void Operation1_Task(CancellationTokenSource cts)
18     {
19         CancellationToken ct = cts.Token;
20         Task.Factory.StartNew(() => 
21         {
22             //其他操作...
23             //return只對當前子線程有效
24             if (ct.IsCancellationRequested)
25             { return; }
26             //其他操作...
27         },ct);     
28     }
29 
30     //2 使用拋異常的方式
31     private static void Operation2_Task(CancellationTokenSource     cts)
32     {
33         CancellationToken ct = cts.Token; 
34         Task.Factory.StartNew(() =>
35         {
36             //其他操作...
37             ct.ThrowIfCancellationRequested();
38             //其他操作...
39         }, ct);
40     }    

3)等待任務完成

 1 private void WaitFunc()
 2 {
 3     Task task = new Task(() => 
 4     {
 5         //具體操作
 6     });
 7     task.Start();
 8     task.Wait();
 9 }
10 
11 private void WaitAllFunc()
12 {
13     Task task1 = Task.Run(() =>
14     {
15         //具體操作 
16     });
17     Task task2 = Task.Run(() =>
18     {
19         //具體操作 
20     });
21     //等待task1與task2,直到它們完成為止
22     Task.WaitAll(task1, task2);
23 
24     //等待task1與task2,如果超過1000毫秒則返回。
25     Task.WaitAll(new Task[] { task1, task2 },1000);
26 }

4)串聯多個任務

 1 private void contactTasks()
 2 {
 3     var t1 = Task.Factory.StartNew(() =>
 4     {
 5         //具體操作1
 6         //return 返回值;
 7     });
 8 
 9     var t2 = t1.ContinueWith((t) =>
10     {
11         //具體操作2
12         //return 返回值;
13     });
14 
15     var t3 = t2.ContinueWith((t) =>
16     {
17         //具體操作3
18     });
19 
20     var t4 = t1.ContinueWith((t) =>
21     {
22         //具體操作4
23     });
24 
25     var t5 = t1.ContinueWith((t) =>
26     {
27         //具體操作5
28     });
29 
30     Task.WaitAll(t3, t4, t5);
31 }

-----------------------------------------------------------------------------------------

轉載與引用請注明出處。

時間倉促,水平有限,如有不當之處,歡迎指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM