任務表示應完成的某個單元的工作。這個單元的工作可以在單獨的線程中運行,也可以以同步方式啟動一個任務,這需要等待主調用線程。使用任務不僅可以獲得一個抽象層,還可以對底層線程進行很多控制。
1.啟動任務
要啟動任務,可以使用TaskFactory類或Task類的構造函數和Start()方法。Task類的構造函數在創建任務上提供的靈活性較大。
1).任務方法
static object taskMethodLock = new object(); static void TaskMethod(object title) { lock (taskMethodLock) { Console.WriteLine(title); Console.WriteLine("Task id: {0}, thread: {1}", Task.CurrentId == null ? "no task" : Task.CurrentId.ToString(), Thread.CurrentThread.ManagedThreadId); Console.WriteLine("is pooled thread: {0}", Thread.CurrentThread.IsThreadPoolThread); Console.WriteLine("is background thread: {0}", Thread.CurrentThread.IsBackground); Console.WriteLine(); } } View Code2).使用線程池的任務
static void TasksUsingThreadPool() { var tf = new TaskFactory(); Task t1 = tf.StartNew(TaskMethod, "using a task factory"); Task t2 = Task.Factory.StartNew(TaskMethod, "factory via a task"); var t3 = new Task(TaskMethod, "using a task constructor and Start"); t3.Start(); Task t4 = Task.Run(() => TaskMethod("using the Run method")); } View Code執行結果:
3).同步任務
任務也可以同步運行,已相同的線程作為主調用線程。
注:主線程是一個調用前台線程,沒有任務ID,也不是線程池中的線程。
private static void RunSynchronousTask() { TaskMethod("just the main thread"); var t1 = new Task(TaskMethod, "run sync"); t1.RunSynchronously(); } View Code執行結果:
4).使用單獨線程的任務
如果任務的代碼應該長時間運行,就應該使用TaskCreationOptions.LogRunning告訴任務調度器創建一個新線程,而不是使用線程池中的線程。
private static void LongRunningTask() { var t1 = new Task(TaskMethod, "long running", TaskCreationOptions.LongRunning); t1.Start(); } View Code執行結果:
2.Future——任務結果
任務結束時,它可以把一些有用的狀態信息寫到共享對象中。這個對象必須是線程安全的。另一個選項是使用返回某個結果的任務。這種任務也叫Future,因為它返回一個結果。
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); } View Code static void ResultsFromTasks() { 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); } View Code執行結果:
3.連續任務
通過任務,可以指定在任務完成後,應開始運行另一個特定任務。
注:無論前一個任務是如何結束的,前面的連續任務總是在前一個任務結束時啟動。使用TaskContinuationOptions枚舉中的值,可以指定,連續任務只有在起始任務成功(或失敗)結束時啟動。一些可能的值是OnlyOnFaulted、NotOnFaulted、OnlyOnCanceled和OnlyOnRanToCompletion。
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); } static void DoOnError(Task t) { Console.WriteLine("task {0} had an error!", t.Id); Console.WriteLine("my id {0}", Task.CurrentId); Console.WriteLine("do some cleanup"); } View Code static void ContinuationTask() { Task t1 = new Task(DoOnFirst); Task t2 = t1.ContinueWith(DoOnSecond); Task t3 = t1.ContinueWith(DoOnSecond); Task t4 = t2.ContinueWith(DoOnSecond); Task t5 = t1.ContinueWith(DoOnError, TaskContinuationOptions.OnlyOnFaulted); t1.Start(); Thread.Sleep(5000); } View Code執行結果:
4.任務層次結構
利用任務連續性,可以在一個任務結束後啟動另一個任務。任務也可以構成一個層次結構。一個任務啟動一個新任務時,就啟動了一個父/子層次結構。
如果父任務在子任務之前結束,父任務的狀態就顯示為:WaitingForChildrenToComplete。所有的子任務也結束時,父任務的狀態就變成RanToCompletion。
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); // , TaskCreationOptions.DetachedFromParent); child.Start(); Thread.Sleep(1000); Console.WriteLine("parent started child"); // Thread.Sleep(3000); } static void ChildTask() { // Console.WriteLine("task id {0}, parent: {1}", Task.Current.Id, Task.Current.Parent.Id); Console.WriteLine("child"); Thread.Sleep(5000); Console.WriteLine("child finished"); } View Code執行結果: