任务并行库-处理任务中的异常

  注意:返回void的异常方法不会等待。这是因为从async void方法抛出的异常无法捕获,因此,异步方法最好返回一个Task类型。处理程序方法或者重写基类方法不受此规则限制。

  异步方法的异常较好的一个处理方式,就是使用await关键字,将其放在try/catch语句中。如下:

  

public static async Task ThrowExcrptionAsync(int ms, string message)
        {
            await Task.Delay(ms);
            throw new Exception(message);
        }

 public static async Task Main(string[] args)
        {
            //以下语句不会捕捉到异常(方法已经执行完毕,而throw new Exception(message)这句话还没执行,所以上面这段代码并不会捕获到异常)
            try
            {
               ThrowExcrptionAsync(2000, "first");
            }
            catch (Exception e)
            {
               Console.WriteLine(e.Message);
            }
            Console.ReadKey();

      try { await ThrowExcrptionAsync(2000, "first"); } //使用await关键字捕捉异常
      catch (Exception e)
      {
        Console.WriteLine(e.Message); } Console.ReadKey();
      } }

  在任务中,处理异常和其它异步方式处理异常类似,如果能在所发生异常的线程中处理,那么不要在其它地方处理。但是对于一些不可预料的异常,那么可以通过几种方式来处理。

  可以通过访问task.Result属性来处理异常,因为访问这个属性的Get方法会使当前线程等待直到该任务完成,并将异常传播给当前线程,这样就可以通过try catch语句块来捕获异常。另外使用task.GetAwaiter().GetResult()方法和第使用task.Result类似,同样可以捕获异常。如果是要捕获多个任务中的异常错误,那么可以通过ContinueWith()方法来处理

具体如何实现,演示代码如下所示。

static void Main(string[] args)
{
    Task<int> task;
    // 在主线程中调用 task.Result task中的异常信息会直接抛出到 主线程中
    try
    {
        task = Task.Run(() => TaskMethod("Task 1", 2));
        int result = task.Result;
        WriteLine($"结果为: {result}");
    }
    catch (Exception ex)
    {
        WriteLine($"异常被捕捉:{ex.Message}");
    }
    WriteLine("------------------------------------------------");
    WriteLine();

    // 同上 只是访问Result的方式不同
    try
    {
        task = Task.Run(() => TaskMethod("Task 2", 2));
        int result = task.GetAwaiter().GetResult();
        WriteLine($"结果为:{result}");
    }
    catch (Exception ex)
    {
        WriteLine($"异常被捕捉: {ex.Message}");
    }
    WriteLine("----------------------------------------------");
    WriteLine();

    var t1 = new Task<int>(() => TaskMethod("Task 3", 3));
    var t2 = new Task<int>(() => TaskMethod("Task 4", 4));

    var complexTask = Task.WhenAll(t1, t2);
    // 通过ContinueWith TaskContinuationOptions.OnlyOnFaulted的方式 如果task出现异常 那么才会执行该方法
    var exceptionHandler = complexTask.ContinueWith(t => {
        WriteLine($"异常被捕捉:{t.Exception.Message}");
        foreach (var ex in t.Exception.InnerExceptions)
        {
            WriteLine($"-------------------------- {ex.Message}");
        }
    },TaskContinuationOptions.OnlyOnFaulted);

    t1.Start();
    t2.Start();

    ReadLine();
}

static int TaskMethod(string name, int seconds)
{
    WriteLine($"任务运行在{CurrentThread.ManagedThreadId}上. 是否为线程池线程:{CurrentThread.IsThreadPoolThread}");

    Sleep(TimeSpan.FromSeconds(seconds));
    // 人为抛出一个异常
    throw new Exception("Boom!");
    return 42 * seconds;
}

 

原文地址:https://www.cnblogs.com/gougou1981/p/12624514.html