c# 基于任务的异步编程模式(TAP)的异常处理
作者:一只独行的猿 发布时间:2023-08-03 15:44:06
在前面讲到了《基于任务的异步编程模式(TAP)》,但是如果调用异步方法,没有等待,那么调用异步方法的线程中使用传统的try/catch块是不能捕获到异步方法中的异常。因为在异步方法执行出现异常之前,已经执行完毕。
1、没有等待的调用异步方法
ThrowAfter方法是在一定延迟后抛出一个异常:
private async Task ThrowAfter(int ms,string message)
{
await Task.Delay(ms);
Console.WriteLine("异步任务随后将抛出异常。");
throw new Exception(message);
}
DontHandle方法在调用异步方法时,由于有滞后性,所以使用try...catch...不能捕获到异步方法中的异常。
public void DontHandle()
{
try
{
ThrowAfter(200, "异步方法抛出的异常");
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("完成方法:DontHandle");
}
注意:返回void的异步方法不会等待。因为从async void方法抛出的异常无法捕获。因此,异步方法最好返回一个Task类型。
2、异步方法的异常处理
异步方法异常的比较好的处理方式使使用await关键字,将其放在try/catch语句中。
public async void HandleOneError()
{
Console.WriteLine("HandleOneError方法开始执行。。。");
try
{
await ThrowAfter(2000, "异步方法抛出的异常");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("完成方法:HandleOneError");
}
调用ThrowAfter方法后,HandleOneError会释放线程,但它会在任务完成时保持对任务的引用。当异步方法抛出异常,会调用匹配的catch块内的代码。
3、多个异步方法的异常处理
如果调用多个异步方法,会有多个抛出异常,在捕获异常时就会有问题。
public async void StartTwoTasks()
{
Console.WriteLine("StartTwoTasks方法开始执行。。。");
try
{
await ThrowAfter(2000, "first");//先执行该方法
await ThrowAfter(1000, "Second");//第一个异步方法正常执行完后才会执行该方法
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("完成方法:StartTwoTasks");
}
StartTwoTasks方法中,调用了两个异步方法。理论上认为,当第一个异步方法执行完,抛出异常后,紧接着就会调用第二个异步方法,并抛出异常。但实际上是第一个异步方法抛出异常之后,就会被catch捕获,并不会执行第二个异步方法。因为这种类型中,在“基于任务的异步编程模式(TAP)”一文中解释过,这种调用方法是等待第一个异步方法执行结束后,调用函数的线程控制权才会调用第二个异步方法,多个异步方法以此类推。但是当时我们使用了Task类中的WhenAll方法同时等待多个任务全部执行完,才执行后面的代码。
public async void StartTwoTasksParallel()
{
Console.WriteLine("StartTwoTasksParallel方法开始执行。。。");
try
{
Task t1 = ThrowAfter(2000, "first");//先执行该方法
Task t2 = ThrowAfter(1000, "Second");//第一个异步方法执行完后才会执行该方法
await Task.WhenAll(t1, t2);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("完成方法:StartTwoTasksParallel");
}
StartTwoTasksParallel方法使用Task类的WhenAll方法,并行调用两个不关联的异步方法。该方法将等待所有任务结束后才结束调用,不论任何一个抛出异常都不会影响其他任务。但是,该方法只会捕获第一个异常(先抛出异常的任务),其他异常将不会被显示。
有一种方法可以获取所有任务的异常信息,就是在try块外声明任务变量t1和t2,让这两个变量在catch块内访问。在catch块中检测任务的IsFaulted属性确认任务的状态,以判定是否出现异常,然后通过Task类的Exception.InnerException访问异常信息本身。
4、使用AggregateException信息
Task.WhenAll方法返回一个Task的结果变量。catch语句只会捕捉到所有异步任务中的第一个异常,但是Task.WhenAll方法返回的Task类型结果变量中会包含所有任务都出现的异常。外部结果任务的Exception属性是一个AggregateException类型,显示所有异常只需要遍历结果任务中的Exception的InnerExceptions属性即可。
public async void ShowAggregatedException()
{
Console.WriteLine("ShowAggregatedException方法开始执行。。。");
Task taskResult = null;
try
{
Task t1 = ThrowAfter(2000, "first");//先执行该方法
Task t2 = ThrowAfter(1000, "second");//第一个异步方法执行完后才会执行该方法
Task t3 = ThrowAfter(1500, "third");//第一个异步方法执行完后才会执行该方法
await (taskResult = Task.WhenAll(t1, t2, t3));
}
catch (Exception ex)
{
Console.WriteLine("handle {0}",ex.Message);
foreach (Exception ex1 in taskResult.Exception.InnerExceptions)
{
Console.WriteLine("Inner exception {0}", ex1.Message);
}
}
Console.WriteLine("完成方法:ShowAggregatedException");
}
来源:https://www.cnblogs.com/pilgrim/p/9147840.html


猜你喜欢
- 前言在日常开发中我们经常会将JSON、XML、HTML、SQL、Regex等字符串拷贝粘贴到我们的代码中,而这些字符串往往包含很多的引号&q
- 前言很久没有写关于 Spring 的文章了,最近在系统梳理 Dubbo 代码的过程中发现了 XML schema 这个被遗漏的知识点。由于工
- 一个简单的网格布局activity_main.xml<?xml version="1.0" encoding=&q
- JPA JpaRepository接口的使用SpringData的所有接口CrudRepository接口 ,其中提供了这些方法提供使用,同
- 目录一、抽象类1.抽象类概述1.1 为什么要有抽象类?(抽象类的作用)1.2 抽象类的定义2. 抽象类特点3.抽象类成员特点4.抽象类案例二
- 前言牛顿摆大家应该都不陌生,也叫碰碰球、永动球(理论情况下),那么今天我们用Flutter实现这么一个理论中的永动球,可以作为加载Loadi
- 本人工作有一个月多了。对于android很多东西,都有了新的了解或者说真正的掌握。为了让更多的像我这样的小白少走弯路,所以我会坚持将我在工作
- instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为:boolean result = o
- 前言:事情是这样的:运营人员反馈,通过Excel导入数据时,有一部分成功了,有一部分未导入。初步猜测,是事务未生效导致的。查看代码,发现导入
- 本文汇总了常用的DateTime日期类型格式化显示方法,方便读者在使用的时候参考借鉴一下。具体如下所示:1.绑定时格式化日期方法:<A
- 前言在工作中,比如要实现一个功能,前端传什么参数,后端的controller层中怎么接收参数 ,封装成了什么实体对象,有些参数是在URL上使
- 本文实例为大家分享了Java实现简单学生管理系统的具体代码,供大家参考,具体内容如下名为StudentManageTest的Java测试类i
- 对于javascript的冒泡,我一直误解它了,冒泡,即是从底层往外blow blow blow ...惭愧的是,我一直以为阻止冒泡是阻止父
- 在javaweb中写了一个图片的链接,可以打开预览,另外提供一个下载功能。以下是预览代码,没什么好说的;href若连接的是一个压缩包文件之类
- 1、Spring Boot跨域配置有两种方法在后端使用Spring Boot。Spring Boot跨域非常简单,只需书写以下代码即可。@C
- 异常方法//返回此可抛出对象的详细信息消息字符串public String getMessage() //将此可抛发对象及其回溯到标准错误流
- 工具:jdk1.8win10spring5.01.准备工作:下载Spring开发应用的插件,api1.spring插件包:springsou
- 问题描述Spring Cache提供的@Cacheable注解不支持配置过期时间,还有缓存的自动刷新。我们可以通过配置CacheManneg
- strings.xml 有很多需要注意的地方和一些小技巧,知道了这些可以让你的 Android 应用更加规范易用,感兴趣的小伙伴们可以参考一
- 可编程的配置方式-1如果在配置cfg.xml的时候,不想在里面配置hbm.xml怎么办呢?可在程序里使用可编程的配置方式,也就是使用程序来指