基于任务的异步编程模式(TAP)的错误处理
在前面讲到了《基于任务的异步编程模式(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(, "异步方法抛出的异常");
}
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(, "异步方法抛出的异常");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("完成方法:HandleOneError");
}
调用ThrowAfter方法后,HandleOneError会释放线程,但它会在任务完成时保持对任务的引用。当异步方法抛出异常,会调用匹配的catch块内的代码。
3、多个异步方法的异常处理
如果调用多个异步方法,会有多个抛出异常,在捕获异常时就会有问题。
public async void StartTwoTasks()
{
Console.WriteLine("StartTwoTasks方法开始执行。。。");
try
{
await ThrowAfter(, "first");//先执行该方法
await ThrowAfter(, "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(, "first");//先执行该方法
Task t2 = ThrowAfter(, "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(, "first");//先执行该方法
Task t2 = ThrowAfter(, "second");//第一个异步方法执行完后才会执行该方法
Task t3 = ThrowAfter(, "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");
}
基于任务的异步编程模式(TAP)的错误处理的更多相关文章
- 基于任务的异步编程模式(TAP)
异步编程是C#5.0的一个重要改进,提供两个关键字:async和await.使用异步编程,方法的调用是在后台运行(通常在线程或任务的帮助下),但不会阻塞调用线程.异步模式分为3种:异步模式.基于事件的 ...
- 二、基于事件的异步编程模式(EAP)
一.引言 在上一个专题中为大家介绍了.NET 1.0中提出来的异步编程模式--APM,虽然APM为我们实现异步编程提供了一定的支持,同时它也存在着一些明显的问题--不支持对异步操作的取消和没有提供对进 ...
- 基于任务的异步编程模式,Task-based Asynchronous Pattern
术语: APM 异步编程模型,Asynchronous Programming Model,其中异步操作由一对 Begin/End 方法(如 FileStream.BeginRea ...
- 异步编程(二)基于事件的异步编程模式 (EAP)
一.引言 在上一个专题中为大家介绍了.NET 1.0中提出来的异步编程模式——APM,虽然APM为我们实现异步编程提供了一定的支持,同时它也存在着一些明显的问题——不支持对异步操作的取消和没有提供对进 ...
- .Net Core自实现CLR异步编程模式(Asynchronous programming patterns)
最近在看一个线程框架,对.Net的异步编程模型很感兴趣,所以在这里实现CLR定义的异步编程模型,在CLR里有三种异步模式如下,如果不了解的可以详细看MSDN 文档Asynchronous progra ...
- C#中的异步编程模式
异步编程模型(APM) 基于事件的异步编程模式 基于任务的异步模式 Async Await编程 关于C#,可以看看Learning Hard的博客
- .NET “底层”异步编程模式——异步编程模型(Asynchronous Programming Model,APM)
本文内容 异步编程类型 异步编程模型(APM) 参考资料 首先澄清,异步编程模式(Asynchronous Programming Patterns)与异步编程模型(Asynchronous Prog ...
- [.net 多线程]异步编程模式
.NET中的异步编程 - EAP/APM 从.NET 4.5开始,支持的三种异步编程模式: 基于事件的异步编程设计模式 (EAP,Event-based Asynchronous Pattern) 异 ...
- .NET异步编程模式(一)
.NET 提供了三种异步编程模型 TAP - task-based asynchronous pattern APM - asynchronous programming model EAP - ev ...
随机推荐
- logback高级特性二 异步记录日志
问题描述: 下图中JProfiler可看出logback的日志输出占了64%的cpu消耗 优化方案: 1. 这部分写日志的代码写了一些报文数据,确实是比较大的字符串.先禁掉控制台输出,生产环境也不需要 ...
- Java-Maven-Runoob:Maven 插件
ylbtech-Java-Maven-Runoob:Maven 插件 1.返回顶部 1. Maven 插件 Maven 有以下三个标准的生命周期: clean:项目清理的处理 default(或 bu ...
- laravel安装初体验
1.github下载laravel 2.通过composer安装相应的库 composer config repo.packagist composer https://packagist.phpco ...
- jQuery解析JSON出现SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data
SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data 我在使用$.parseJSON解析后 ...
- 关系数据库SQL复习
1.1 SQL的概述 SQL(Structured Query Language)结构化查询语言,是关系数据库的标准语言 SQL是一个通用的.功能极强的关系数据库语言 1.2 SQL的特点 1. 综合 ...
- Python常用算法
本节内容 算法定义 时间复杂度 空间复杂度 常用算法实例 1.算法定义 算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机 ...
- oracle一个创建用户、创建表空间、授权、建表的完整过程
1.首先我们可以用scott用户以sysdba的身份登录oracle. conn scott/tiger as sysdba 2.然后我就可以来创建用户了. create user zzg ident ...
- NetworkView
[游戏Server中Server的类别] There are two common and proven approaches to structuring a network game which ...
- ORA-01940:无法删除当前已链接的用户
(1)查看用户的连接状况 select user name, sid, serial# from v$session; (2)找到要删除用户的sid,和serial,并删除 例如要删除用户nc633t ...
- EF的左连接查询
在EF中,当在dbset使用join关联多表查询时,连接查询的表如果没有建立相应的外键关系时,EF生成的SQL语句是inner join(内联),对于inner join,有所了解的同学都知道,很多时 ...