为什么不要使用 Async Void ?
问题
在使用 Abp 框架的后台作业时,当后台作业抛出异常,会导致整个程序崩溃。在 Abp 框架的底层执行后台作业的时候,有 try/catch 语句块用来捕获后台任务执行时的异常,但是在这里没有生效。
原始代码如下:
public class TestAppService : ITestAppService
{
private readonly IBackgroundJobManager _backgroundJobManager;
public TestAppService(IBackgroundJobManager backgroundJobManager)
{
_backgroundJobManager = backgroundJobManager;
}
public Task GetInvalidOperationException()
{
throw new InvalidOperationException("模拟无效操作异常。");
}
public async Task<string> EnqueueJob()
{
await _backgroundJobManager.EnqueueAsync<BG, string>("测试文本。");
return "执行完成。";
}
}
public class BG : BackgroundJob<string>, ITransientDependency
{
private readonly TestAppService _testAppService;
public BG(TestAppService testAppService)
{
_testAppService = testAppService;
}
public override async void Execute(string args)
{
await _testAppService.GetInvalidOperationException();
}
}
调用接口时的效果:

原因
出现这种情况是因为任何异步方法返回 void 时,抛出的异常都会在 async void 方法启动时,处于激活状态的同步上下文 (SynchronizationContext) 触发,我们的所有 Task 都是放在线程池执行的。
所以在上述样例当中,此时 AsyncVoidMethodBuilder.Create() 使用的同步上下文为 null ,这个时候 ThreadPool 就不会捕获异常给原有线程处理,而是直接抛出。
线程池在底层使用 AsyncVoidMethodBuilder.Craete() 所拿到的同步上下文,所捕获异常的代码如下:
internal static void ThrowAsync(Exception exception, SynchronizationContext targetContext)
{
var edi = ExceptionDispatchInfo.Capture(exception);
// 同步上下文是空的,则不会做处理。
if (targetContext != null)
{
try
{
targetContext.Post(state => ((ExceptionDispatchInfo)state).Throw(), edi);
return;
}
catch (Exception postException)
{
edi = ExceptionDispatchInfo.Capture(new AggregateException(exception, postException));
}
}
}
虽然你可以通过挂载 AppDoamin.Current.UnhandledException 来监听异常,不过你是没办法从异常状态恢复的。
参考文章:
Stephen Cleary: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
Jerome Laban's:https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.html
解决
可以使用 AsyncBackgroundJob<TArgs> 替换掉之前的 BackgroundJob<TArgs> ,只需要实现它的 Task ExecuteAsync(TArgs args) 方法即可。
public class BGAsync : AsyncBackgroundJob<string>,ITransientDependency
{
private readonly TestAppService _testAppService;
public BGAsync(TestAppService testAppService)
{
_testAppService = testAppService;
}
protected override async Task ExecuteAsync(string args)
{
await _testAppService.GetInvalidOperationException();
}
}
为什么不要使用 Async Void ?的更多相关文章
- 为什么不要使用 async void?
问题 在使用 Abp 框架的后台作业时,当后台作业抛出异常,会导致整个程序崩溃.在 Abp 框架的底层执行后台作业的时候,有 try/catch 语句块用来捕获后台任务执行时的异常,但是在这里没有生效 ...
- 《C#并发编程经典实例》学习笔记—2.9 处理 async void 方法的异常
问题 需要处理从 async void 方法传递出来的异常. 解决方案 书中建议尽量不写 async void 这样的方法,如果非写不可,建议在方法内部 try catch 所有的代码,即在方法内部处 ...
- 处理async void 方法中无法捕捉异常信息
利用 NuGet库 Nito.AsyncEx 中的 AsyncContext类. 添加NuGet类库,使用AsyncContext AsyncContext.Run(Action action);
- [C#] async 的三大返回类型
async 的三大返回类型 序 博主简单数了下自己发布过的异步文章,已经断断续续 8 篇了,这次我想以 async 的返回类型为例,单独谈谈. 异步方法具有三个可让开发人员选择的返回类型:Task&l ...
- async & await 的前世今生(Updated)
async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们编程埋下了一些隐 ...
- [.NET] 怎样使用 async & await 一步步将同步代码转换为异步编程
怎样使用 async & await 一步步将同步代码转换为异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6079707.html ...
- [.NET] 利用 async & await 进行异步 IO 操作
利用 async & await 进行异步 IO 操作 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6082673.html 序 上次,博主 ...
- await and async
Most people have already heard about the new “async” and “await” functionality coming in Visual Stud ...
- C#~异步编程再续~await与async引起的w3wp.exe崩溃-问题友好的解决
返回目录 关于死锁的原因 理解该死锁的原因在于理解await 处理contexts的方式,默认的,当一个未完成的Task 被await的时候,当前的上下文将在该Task完成的时候重新获得并继续执行剩余 ...
随机推荐
- java读取指定package下的所有class
JAVA如何扫描一个包下面的所有类,并加载到内存中去? spring中有一个<context:component-scan base-package="com.controller& ...
- struts2.3.4.1转换成eclipse项目的过程
1.在本地安装配置maven. 1.1.从maven官网下载,官网地址:http://maven.apache.org/download.cgi 1.2.配置maven环境变量 例如,我的 ...
- ASP.NET Core - VSCode安装和配置
在深入了解ASP.NET Core之前先研究了下主要的两个开发工具(VS 2015和VS Code), VS 2015对Core的支持已经相当的完备,很多操作得到简化用起来很是方便.VS Code是微 ...
- leetcode: 树
1. sum-root-to-leaf-numbers Given a binary tree containing digits from0-9only, each root-to-leaf pat ...
- IOS中 copy ,strong ,weak ,assign使用区别
.@property属性的用法 * weak(assign) : 代理\UI控件 * strong(retain) : 数组.模型)其他对象(除代理\UI控件\字符串以外的对象) * copy ...
- testng失败重跑
重跑失败场景 1.要添加两个文件 背景:因为这里只是想单独展示失败的重跑的案例,所以先暂时把app这块的运行注释掉,只跑一个简单的demo,就一个简单类,类中就3个测试方法,失败重跑的原理是,运行方法 ...
- [pytorch] Pytorch入门
Pytorch入门 简单容易上手,感觉比keras好理解多了,和mxnet很像(似乎mxnet有点借鉴pytorch),记一记. 直接从例子开始学,基础知识咱已经看了很多论文了... import t ...
- 2018年第九届蓝桥杯【C++省赛B组】第四题 测试次数
x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机.各大厂商也就纷纷推出各种耐摔型手机.x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通.x星球 ...
- 剑指offer25 二叉树中和为某一直的路径
先序遍历 class Solution { public: vector<vector<int> > FindPath(TreeNode* root,int expectNum ...
- 使用QT开发GoogleMap瓦片显示和下载工具(1)——QT开发环境准备
由于是第一次使用qt,光是QT的安装和调试就费了好大功夫,汗一个,下面记录下过程和遇到的问题的解决方法吧. 下载QT 直接Google搜索“QT”,进入官网http://qt-project.org/ ...