C#多執行緒程式設計筆記(4.4)-處理Task任務中的異常
阿新 • • 發佈:2019-01-29
近來在學習Eugene Agafonov編寫的《C#多執行緒程式設計實戰》(譯),做些筆記也順便分享一下^-^
using System; using System.Threading.Tasks; using System.Threading; namespace 處理任務中的異常 { class Program { static void Main(string[] args) { Task<int> task; try { task = Task.Run(() => TaskMethod("Task 1", 2)); int result = task.Result; Console.WriteLine("Result: {0}", result); } catch (Exception ex) { Console.WriteLine("Exception caught: {0}", ex); } Console.WriteLine("----------------------------------------"); Console.WriteLine(); try { task = Task.Run(() => TaskMethod("Task 2", 2)); int result = task.GetAwaiter().GetResult(); Console.WriteLine("Result: {0}", result); } catch (Exception ex) { Console.WriteLine("Exception caught: {0}", ex); } Console.WriteLine("----------------------------------------"); Console.WriteLine(); var t1 = new Task<int>(() => TaskMethod("Task 3", 3)); var t2 = new Task<int>(() => TaskMethod("Task 4", 2)); var complexTask = Task.WhenAll(t1, t2); var exceptionHandler = complexTask.ContinueWith(t => Console.WriteLine("Exception caught: {0}", t.Exception), TaskContinuationOptions.OnlyOnFaulted); t1.Start(); t2.Start(); Console.ReadKey(); } static int TaskMethod(string name,int seconds) { Console.WriteLine("Task {0} is running on a thread id {1}.Is thread pool thread: {2}", name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread); Thread.Sleep(TimeSpan.FromSeconds(seconds)); throw new Exception("Boom!"); return 42 * seconds; } } }
當程式啟動時,建立了一個任務並嘗試同步獲取任務結果。Result屬性的Get部分會使當前執行緒等待直到該任務完成,並將異常傳播給當前執行緒。在這種情況下,通過catch程式碼塊可以很容易地捕獲異常,但是該異常是一個被封裝的異常,叫做AggregateException。在本例中,它裡面包含一個異常,因為只有一個任務丟擲了異常。可以訪問InnerException屬性來得到底層異常。
第二個例子與第一個非常相似,不同之處是使用GetAwaiter和GetResult方法來訪問任務結果。這種情況下,無需封裝異常,因為TPL基礎設施會提前該異常。如果只有一個底層任務,那麼一次只能獲取一個原始異常,這種設計非常合適。
最後一個例子展示了兩個任務丟擲異常的情形。現在使用後續操作來處理異常。只有之前的任務完成前有異常時,該後續操作才會被執行。通過給後續操作傳遞TaskContinuationOptions.OnlyOnFaulted選項可以實現該行為。結果打印出了AggregateException,其內部封裝了兩個任務丟擲的異常。