dotnet 警惕 Task 的 ContinueWith 带上 OnlyOnFaulted 参数抛出取消异常
本文记录 dotnet 的一个令人迷惑的设计,在 Task 里,有一个叫 ContinueWith 的方法,此方法可以在 Task 完成时执行传入的委托。在 ContinueWith 方法里面,还有一个可选的 TaskContinuationOptions 参数,在此参数里面传入 OnlyOnFaulted 即可在 Task 出错时才执行传入的委托,然而此行为迷惑的是在 Task 正在执行完成却抛出取消异常
在等待任务执行完成之后,干某个活的事情上,有多个可选方法。一个就是老实使用 await 等待 Task 执行完成,然后再继续编写后续逻辑,如以下代码
await task;
干自己的活();
另一个方法就是通过 ContinueWith 方法,比如在使用 Task.Run 执行某个 Foo 方法之后,再 干自己的活 的代码
var task = Task.Run(Foo).ContinueWith(t =>
{
});
以上的 ContinueWith 方法里面传入的委托是不管 Task 的执行状态,无论是成功还是失败都能进入。如果只期望只有在失败时才进入,可以传入 OnlyOnFaulted 参数,代码如下
var task = Task.Run(Foo).ContinueWith(t =>
{
}, TaskContinuationOptions.OnlyOnFaulted);
然而这里存在一个令人迷惑的行为,大家猜猜,当 Foo 正常执行时,等待上面代码的 task 时,是否会抛出异常
答案是抛出 TaskCanceledException 异常
var task = Task.Run(Foo).ContinueWith(t =>
{
}, TaskContinuationOptions.OnlyOnFaulted);
try
{
await task;
}
catch (TaskCanceledException e)
{
}
static void Foo()
{
}
这是因为 dotnet 认为 ContinueWith 里面的委托被取消了
那如果 Task 执行过程中抛出异常呢?看看下面的代码
var task1 = Task.Run(FooWithException).ContinueWith(t =>
{
}, TaskContinuationOptions.OnlyOnFaulted);
await task1;
static void FooWithException()
{
throw new Exception("lindexi is doubi");
}
可以看到 task1 正常被等待,啥事都没有发生
这么特别诡异起来了,很好就在代码里面挖坑。毕竟写了以上代码的开发者更多的是进行测试 Task 异常的情况。再加上如果偶尔的正常执行完成,抛出的是取消异常,很多开发者都会以为是正常被取消而已
也有伙伴说,那分开两个 Task 等待好了,如以下代码
var task = Task.Run(Foo);
var task1 = task.ContinueWith(t =>
{
}, TaskContinuationOptions.OnlyOnFaulted);
但是以上代码解决不了的问题是,如果期望等待整个大的 Task 执行完成,也就是 Task 和 ContinueWith 里面的内容全部执行完成,那这个逻辑就诡异了
也就是只有在无需等待 ContinueWith 执行结果的情况下,才可以推荐使用 OnlyOnFaulted 参数。没有等待 ContinueWith 执行结果,且刚好 Task 是正常执行的,这是不会将取消异常抛到 UnobservedTaskException 里的
TaskScheduler.UnobservedTaskException += (sender, eventArgs) =>
{
};
在 dotnet 的设计里面,如果一个 Task 存在异常,且这个 Task 的异常没有被任何代码捕获到,将在此 Task 被 GC 时,抛到 UnobservedTaskException 里面。可以通过如上代码的事件,获取到是否存在有 Task 的异常没有被捕获。进入 UnobservedTaskException 事件的异常不会导致应用挂掉,只是用来记录日志或者埋点上报等,让开发者知道有某个 Task 的异常没有被捕获
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin f758059f3f9f9bbfe2e7205a137d2e5b3da31f7a
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin f758059f3f9f9bbfe2e7205a137d2e5b3da31f7a
获取代码之后,进入 HojohoyahobaWayfahurhalqeje 文件夹
更多博客,请参阅我的 博客导航
dotnet 警惕 Task 的 ContinueWith 带上 OnlyOnFaulted 参数抛出取消异常的更多相关文章
- js进阶解决浏览器缓存不能自动更新的问题(在ajax的url上带上一个参数,可以是日期,或者是随机数)(随机数Math.random)(取得日期的毫秒数:new Date().getTime();)
js进阶解决浏览器缓存不能自动更新的问题(在ajax的url上带上一个参数,可以是日期,或者是随机数)(随机数Math.random)(取得日期的毫秒数:new Date().getTime();) ...
- 在XP系统中自带的 msvcrt.dll 和 Vista 中的 msvcrt.dll 版本不同,导致抛出的异常不同
然而,在XP系统中,系统自带的 msvcrt.dll 和 Vista 中的 msvcrt.dll 版本不同, 并没有这个 _except_handler4_common ,结果就出现了启动程序时,遇到 ...
- 记一次asp.net core 在iis上运行抛出502.5错误
asp.net core 在iis上运行抛出502.5异常的部分原因以及解决方案 环境说明 已安装 .net core runtime 2.1.401 已安装 .net core windows ho ...
- 调用远程主机上的 RMI 服务时抛出 java.rmi.ConnectException: Connection refused to host: 127.0.0.1 异常原因及解决方案
最近使用 jmx 遇到一个问题,client/server 同在一台机器上,jmx client能够成功连接 server,如果把 server 移植到另一台机器上192.168.134.128,抛出 ...
- 案例复现,带你分析Priority Blocking Queue比较器异常导致的NPE问题
摘要:本文通过完整的案例复现来演示在什么情况会触发该问题,同时给出了处理建议.希望读者在编程时加以借鉴,避免再次遇到此类问题. 本文分享自华为云社区<Priority Blocking Queu ...
- Asp.net Core dotnet 发布类库文件 带上注释,发布预发行版,带上所有引用
带上注释 效果图 带上所有引用 效果图 预发行版 效果图 由于微软取消了 project.json 这个json 转而用了csproj 用于保存配置 所以懵逼很大一会 资料来源 project.j ...
- 【HDU 4940】Destroy Transportation system(无源无汇带上下界可行流)
Description Tom is a commander, his task is destroying his enemy’s transportation system. Let’s repr ...
- .NetCore HttpClient发送请求的时候为什么自动带上了一个RequestId头部?
奇怪的问题 最近在公司有个系统需要调用第三方的一个webservice.本来调用一个下很简单的事情,使用HttpClient构造一个SOAP请求发送出去拿到XML解析就是了. 可奇怪的是我们的请求在运 ...
- 记得ajax中要带上AntiForgeryToken防止CSRF攻击
经常看到在项目中ajax post数据到服务器不加防伪标记,造成CSRF攻击 在Asp.net Mvc里加入防伪标记很简单在表单中加入Html.AntiForgeryToken()即可. Html.A ...
- ZOJ 2314 带上下界的可行流
对于无源汇问题,方法有两种. 1 从边的角度来处理. 新建超级源汇, 对于每一条有下界的边,x->y, 建立有向边 超级源->y ,容量为x->y下界,建立有向边 x-> 超级 ...
随机推荐
- 记录--Loading 用户体验 - 加载时避免闪烁
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 在切换详情页中有这么一个场景,点击上一条,会显示上一条的详情页,同理,点击下一条,会显示下一条的详情页. 伪代码如下所示: 我们定义了一个 ...
- 看看谷歌如何在目标检测任务使用预训练权值 | CVPR 2022
论文提出能够适配硬件加速的动态网络DS-Net,通过提出的double-headed动态门控来实现动态路由.基于论文提出的高性能网络设计和IEB.SGS训练策略,仅用1/2-1/4的计算量就能达到静态 ...
- 郑州IT微信交流群期待你的加入
我建了一个郑州IT微信交流群,找工作,找项目,人员招聘的都可以加入. 你有一个苹果,我有一个香蕉,合在一起,我们每个人都可以吃到两种水果了.广结人缘,扩大自己的人脉. 可以加我个人微信,拉你进群.
- 并发框架 LMAX Disruptor
Introduction Michael Barker edited this page on 2 Mar 2015 · 8 revisions The best way to understan ...
- Mybatis-Plus框架的BaseMapper的insert方法和自定义mapper里面的insert方法会用哪个
在Mybatis-Plus框架中,当一个接口继承了BaseMapper接口,并且绑定了一个xml文件时,如果这个接口和xml文件中都定义了相同的方法,那么在调用该方法时,会优先调用xml文件中的方法, ...
- 数据解析之Beautifulsoup
一.BeautifulSoup的简单使用 简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据.官方解释如下: Beautiful Soup提供一些简单的.pyt ...
- 7 JavaScript循环语句
7 循环语句 在js中有三种循环语句. 首先是while循环. 它的逻辑和咱们python中的while几乎一模一样, 就是符号上有些许的区别. // 语法 while(条件){ 循环体 -> ...
- #虚树,树形dp#洛谷 4103 [HEOI2014]大工程
题目 分析 建一棵虚树,然后树形dp,维护最长/短链和次长/短链, 对于第一个就是统计每条边有多少个点对经过就可以了 代码 #include <cstdio> #include <c ...
- synchronized解锁源码分析
上篇花了很大篇幅写了synchronized的加锁流程,并对比了ReentrantLock的设计,这篇我们收个尾,来聊一聊解锁流程,本来准备一章解决的,写着写着觉得内容过多,其实上一篇和Reentra ...
- 如何通过 kubectl 进入 node shell
概述 假设这样一个场景: 生产环境中,Node 都需要通过堡垒机登录,但是 kubectl 是可以直接在个人电脑上登录的. 这种场景下,我想要通过 kubectl 登录到 K8S 集群里的 Node, ...