多线程编程学习笔记——任务并行库(三)
接上文 多線程編程學習筆記——任務并行庫(一)
接上文?多線程編程學習筆記——任務并行庫(二)
?
六、?? 實現取消選項
????????? 本示例學習如何實現基于Task的異步操作進行取消流程,以及在任務真正運行前如何知道任務已經被取消。
1.代碼如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ThreadTPLDemo { class Program{static void Main(string[] args){Console.WriteLine(" 將Task中實現取消操作。。。");var cts =new CancellationTokenSource();var task1 = new Task<int>(() => RunTask("任務 1",10, cts.Token),cts.Token); Console.WriteLine(" ——task1 狀態—{0}", task1.Status);cts.Cancel();Console.WriteLine(" ——取消——task1 狀態—{0}—",task1.Status); Console.WriteLine(" ——task1 在出錯之前 取消了操作—");//task1.Start();cts = new CancellationTokenSource();var task2 = new Task<int>(() => RunTask("任務 2", 10, cts.Token),cts.Token);task2.Start();for (int i = 0; i < 5; i++){Thread.Sleep(500);Console.WriteLine(" ——task2 狀態—{0}", task2.Status);}cts.Cancel();for (int i = 0; i < 5; i++){Thread.Sleep(500); Console.WriteLine(" ——task2 狀態—{0}", task2.Status);}Console.WriteLine(" ——任務Task 運行結果—{0}", task2.Result);Thread.Sleep(2000); Console.Read(); }private static int RunTask(string name,int seconds,CancellationToken token){ Console.WriteLine("Task {0} 運行在線程={1}中,是否在線程池 :{2}",name,Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.IsThreadPoolThread);for (int i = 0; i < seconds; i++){Thread.Sleep(TimeSpan.FromSeconds(1));if (token.IsCancellationRequested){//取消操作,返回-1;return -1;}} return 42 * seconds;}} }
?
2.程序運行結果如下圖。
????? 首先我們來看task1的創建代碼,我們給底層任務傳遞一次取消標志,然后給任務的構造函數又傳遞了一次。
????? 那為什么要傳遞兩次取消標志呢?
????? 因為如果在task實際啟動之前取消它,則TPL的底層有責任處理這個取消操作。經過TPL底層處理過取消操作的task,如果再次啟動,則會拋出異常。如下圖。
?
?
???????? 然后需要我們自己寫代碼處理取消操作,在取消操作之后,任務的狀態仍然是RanToCompletion,從TPL來角度來講,這個task已經完成。
?
七、?? 處理task中的異常
????????? 通過此示例我們學習如何在task中拋出不同情況的異常,以及如何獲取這些異常信息。
?1.程序代碼如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks;namespace ThreadTPLDemo {class Program{static void Main(string[] args){Console.WriteLine(" 處理Task中的異常信息。。。。。");try{var task1 = Task.Run(() => RunTask("任務 1", 2));int result = task1.Result;Console.WriteLine(" ——task1 狀態—{0}---值=={1}", task1.Status,result);}catch (Exception ex){Console.WriteLine(" ——task1 錯誤信息—{0};innerException--{1}", ex.Message,ex.InnerException==null?string.Empty:ex.InnerException.Message);} Console.WriteLine(" ——————————————————————");try{var task2 = Task.Run(() => RunTask("任務 2", 2));int result = task2.GetAwaiter().GetResult();Console.WriteLine(" ——task2 狀態—{0}---值=={1}", task2.Status, result);}catch (Exception ex){Console.WriteLine(" ——task2 錯誤信息—{0}", ex.Message);} Console.WriteLine(" ——————————————————————");var task3 = new Task<int>(() => RunTask("任務 3", 2));var task4 = new Task<int>(() => RunTask("任務 4", 2));var completeTaskAll = Task.WhenAll(task3, task4);var exception = completeTaskAll.ContinueWith(t => Console.WriteLine(" ——task 錯誤信息—{0}", t.Exception)
, TaskContinuationOptions.OnlyOnFaulted);task3.Start();task4.Start(); Thread.Sleep(7000); Console.Read();}private static int RunTask(string name,int seconds){ Console.WriteLine("Task {0} 運行在線程={1}中,是否在線程池 :{2}",name,
Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.IsThreadPoolThread); Thread.Sleep(TimeSpan.FromSeconds(seconds));throw new Exception("測試錯誤信息!");return 42 * seconds;}} }
?
2.程序運行結果,如下圖。
?
?????? ? 當程序啟動時,創建一個任務task1并嘗試同步獲取結果。Result屬性的Get部分會使當前線程等待直到這個任務完成,并將異常傳播給當前線程。在這種情況下,通過catch代碼塊可以很容易地捕捉異常,不過這個異常是封裝異常。所以可以訪問InnerException來獲取異常信息。
? ? ? ?? Task2使用GetAwaiter與GetResult來獲取任務結果。這種情況下,不需要封裝異常,TPL會提取異常。如果底層只有一個task,一次只提取一個異常。
最后一個示例是兩個任務(task3,task4)拋出異常的情況 。通過后續操作來處理異常,只有之前的任務完成之前有異常,這個后續操作才會被觸發 。通過后續操作傳遞TaskContinuationOption.OnlyOrFaulted選項來實現 ,在拋出的異常中封裝了兩個異常。
轉載于:https://www.cnblogs.com/chillsrc/p/7993492.html
總結
以上是生活随笔為你收集整理的多线程编程学习笔记——任务并行库(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Python】Python中的列表操作
- 下一篇: while循环打印*菱形