4.8 处理任务中的异常
下面这个例子讨论了任务当中抛出异常,以及任务异常的获取
class Program
{
static void Main(string[] args)
{
//声明一个任务
Task<int> task;
//第一种方式,普通的try...catch捕获异常
try
{
task = Task.Run(() => TaskMethod("Task 1", ));
int result = task.Result;
Console.WriteLine("Result: {0}", result);
}
catch (Exception ex)
{
//这里捕获的异常是一个被封装的异常,叫做AggregateException
Console.WriteLine("Exception caught: {0}", ex);
Console.WriteLine("----------------------------------------------");
//本例中AggregateException之中只有一个异常,因为只有一个任务抛出了异常
Console.WriteLine("InnerException is {0}",ex.InnerException.ToString());
}
Console.WriteLine("----------------------------------------------");
Console.WriteLine(); //第二种方式是采用GetAwaiter().GetResult()方法来访问任务结果,这种方式可以提取没有封装的异常
try
{
task = Task.Run(() => TaskMethod("Task 2", ));
int result = task.GetAwaiter().GetResult();
Console.WriteLine("Result: {0}", result);
}
catch (Exception ex)
{
Console.WriteLine("Exception caught: {0}", ex);
}
Console.WriteLine("----------------------------------------------");
Console.WriteLine(); //第三个demo展示了两个任务抛出异常的情形。
var t1 = new Task<int>(() => TaskMethod("Task 3", ));
var t2 = new Task<int>(() => TaskMethod("Task 4", ));
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());
} 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 * seconds;
}
}
结果如下
第一个demo
第二个demo
第三个demo
4.9 并行运行任务
这个小节主要讲述了Task.WhenAll()和Task.WhenAny()这两个方法,一个是等待所有任务全执行后的操作,一个是等待任何一个任务执行完的操作。
例子:
class Program
{
static void Main(string[] args)
{
//创建两个任务firstTask和secondTask
var firstTask = new Task<int>(() => TaskMethod("First Task", ));
var secondTask = new Task<int>(() => TaskMethod("Second Task", ));
//借助Task.WhenAll()方法创建第三个任务,该任务会在前两个任务完成后完成
var whenAllTask = Task.WhenAll(firstTask, secondTask);
//whenAllTask任务结束以后会产生一个结果数组,
//对应的第一个元素是第一个任务结果,第二个元素对应的是第二个任务结果...
whenAllTask.ContinueWith(t =>
Console.WriteLine("The first answer is {0}, the second is {1}", t.Result[], t.Result[]),
TaskContinuationOptions.OnlyOnRanToCompletion
); firstTask.Start();
secondTask.Start(); Thread.Sleep(TimeSpan.FromSeconds()); //这个demo,展示了启动一系列任务运行的过程
var tasks = new List<Task<int>>();
for (int i = ; i < ; i++)
{
int counter = i;
var task = new Task<int>(() => TaskMethod(string.Format("Task {0}", counter), counter));
tasks.Add(task);
task.Start();
} while (tasks.Count > )
{
//使用Task.WhenAny()方法等待任务当中的任何一个任务完成
var completedTask = Task.WhenAny(tasks).Result;
//每当一个任务完成,就把他从任务列表移除,直到任务列表为空
tasks.Remove(completedTask);
Console.WriteLine("A task has been completed with result {0}.", completedTask.Result);
} Thread.Sleep(TimeSpan.FromSeconds());
} 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));
return * seconds
}