Skip to content

C# 多线程 04-使用任务平行库 07-处理任务中的异常

🏷️ 《C# 多线程》

处理任务中的异常

csharp
/// <summary>
/// 处理任务中的异常
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
    Task<int> task;
    try
    {
        task = Task.Run(() => TaskMethod("Task 1", 2));
        // 尝试同步获取 task 的结果
        // 捕获的异常是一个被封装的异常(AggregateExcption),可以访问 InnerException 获取底层异常
        int result = task.Result;
        Console.WriteLine($"Result: {result}");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception caught: {ex}");
    }
    Console.WriteLine("----------------------------------------");
    Console.WriteLine();

    try
    {
        task = Task.Run(() => TaskMethod("Task 2", 2));
        // 使用 GetAwaiter 和 GetResult 方法获取任务结果
        // 这种情况下不会封装异常,因为 TPL 基础设施会提取该异常。
        // 如果只有一个底层任务,那么一次只能获取一个原始异常。
        int result = task.GetAwaiter().GetResult();
        Console.WriteLine($"Result: {result}");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception caught: {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);
    // 待 t1 和 t2 都结束后才会打印异常
    // 异常类型为 AggregateExcption,其内部封装了 2 个任务抛出的异常
    var exceptionHandler = complexTask.ContinueWith(
        t => Console.WriteLine($"Exception caught: {t.Exception}"),
        TaskContinuationOptions.OnlyOnFaulted);
    t1.Start();
    t2.Start();
    Thread.Sleep(TimeSpan.FromSeconds(5));
    Console.ReadLine();
}

static int TaskMethod(string name, int seconds)
{
    Console.WriteLine($"Task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}. " +
        $"Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}");
    Thread.Sleep(TimeSpan.FromSeconds(seconds));
    throw new Exception("Boom!");
    return 42 * seconds;
}

打印结果

txt
Task Task 1 is running on a thread id 3. Is thread pool thread: True
Exception caught: System.AggregateException: 发生一个或多个错误。 ---> System.Ex
ception: Boom!
   在 Recipe4_7.Program.TaskMethod(String name, Int32 seconds) 位置 C:\Users\liu
jiajia\Source\Repos\learn-multi-threading\Recipe4-7\Program.cs:行号 63
   在 Recipe4_7.Program.<>c.<Main>b__0_0() 位置 C:\Users\liujiajia\Source\Repos\
learn-multi-threading\Recipe4-7\Program.cs:行号 18
   在 System.Threading.Tasks.Task`1.InnerInvoke()
   在 System.Threading.Tasks.Task.Execute()
   --- 内部异常堆栈跟踪的结尾 ---
   在 System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceled
Exceptions)
   在 System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotifica
tion)
   在 System.Threading.Tasks.Task`1.get_Result()
   在 Recipe4_7.Program.Main(String[] args) 位置 C:\Users\liujiajia\Source\Repos
\learn-multi-threading\Recipe4-7\Program.cs:行号 20
---> (内部异常 #0) System.Exception: Boom!
   在 Recipe4_7.Program.TaskMethod(String name, Int32 seconds) 位置 C:\Users\liu
jiajia\Source\Repos\learn-multi-threading\Recipe4-7\Program.cs:行号 63
   在 Recipe4_7.Program.<>c.<Main>b__0_0() 位置 C:\Users\liujiajia\Source\Repos\
learn-multi-threading\Recipe4-7\Program.cs:行号 18
   在 System.Threading.Tasks.Task`1.InnerInvoke()
   在 System.Threading.Tasks.Task.Execute()<---

----------------------------------------

Task Task 2 is running on a thread id 4. Is thread pool thread: True
Exception caught: System.Exception: Boom!
   在 Recipe4_7.Program.TaskMethod(String name, Int32 seconds) 位置 C:\Users\liu
jiajia\Source\Repos\learn-multi-threading\Recipe4-7\Program.cs:行号 63
   在 Recipe4_7.Program.<>c.<Main>b__0_1() 位置 C:\Users\liujiajia\Source\Repos\
learn-multi-threading\Recipe4-7\Program.cs:行号 32
   在 System.Threading.Tasks.Task`1.InnerInvoke()
   在 System.Threading.Tasks.Task.Execute()
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
   在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   在 System.Runtime.CompilerServ