【C#】47. Task 的异常处理

来源:互联网 发布:mysql中格式化时间 编辑:程序博客网 时间:2024/05/29 15:58

就像在讨论线程的时候我们说过,要在线程调用的函数里面做try catch处理,如果在其他线程中使用try catch是无法正常捕获异常。Task也一样,基本原理就是一个线程没办法捕获另一个线程的异常

static int TaskMethod(string name, int seconds){Console.WriteLine("Task {0} 运行在线程 {1} 上。是否是线程池线程: {2}",name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);throw new Exception("Boom!");return 42 * seconds;}

TaskMethod内部并没用try catch 处理,只是抛出一个异常(Boom)。

首先,我们来看一下在主线程中加入Try catch能否正确处理异常:

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();




结果正如我们所预期的那样,并不能正确的捕获异常。

如果我们使用GetAwaiter和GetResult方法来访问任务结果,当程序运行(Debug)到异常处会停止并且提示错误(如上图),但“继续”后,就会发现主线程中正确捕获错误

try{task = Task.Run(() => TaskMethod("Task 2", 2));int result = task.GetAwaiter().GetResult(); //注意这里使用了GetAwaiter和GetResultConsole.WriteLine("Result: {0}", result);}catch (Exception ex){Console.WriteLine("Exception caught: {0}", ex);}


同理,对于多个任务,如果其中几个任务发生异常,那么我们也可以通过后续操作(ContinueWith)结合后续操作状态条件(OnlyOnFault)从而在其他线程中捕获异常。注意:捕获的异常为AggregateException,其内部封装了两个任务抛出的异常

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();Thread.Sleep(TimeSpan.FromSeconds(5));Console.Read();


0 0
原创粉丝点击