为什么不要使用 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
布鲁克石:https://www.cnblogs.com/brookshi/p/5240510.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(); }}
原文地址:https://www.cnblogs.com/myzony/p/10647460.html
.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com
为什么不要使用 async void相关推荐
- C# async await 学习笔记2
C# async await 学习笔记1(http://www.cnblogs.com/siso/p/3691059.html) 提到了ThreadId是一样的,突然想到在WinForm中,非UI线程 ...
- C# 中的Async 和 Await 的用法详解
众所周知C#提供Async和Await关键字来实现异步编程.在本文中,我们将共同探讨并介绍什么是Async 和 Await,以及如何在C#中使用Async 和 Await. 同样本文的内容也大多是翻译 ...
- [转]小心C# 5.0 中的await and async模式造成的死锁
原文链接 https://www.cnblogs.com/OpenCoder/p/4434574.html 内容 UI Example Consider the example below. A bu ...
- C# 5.0中引入了async 和 await
C# 5.0中引入了async 和 await.这两个关键字可以让你更方便的写出异步代码. 看个例子: [csharp] view plaincopy public class MyClass { p ...
- 多线程编程学习笔记——async和await(三)
接上文 多线程编程学习笔记--async和await(一) 接上文 多线程编程学习笔记--async和await(二) 五. 处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多 ...
- 异步/等待-什么时候返回Task vs void?
本文翻译自:async/await - when to return a Task vs void? Under what scenarios would one want to use 在什么情况下 ...
- 异步的两种写法: async 与 BeginInvoke
现在要实现异步只要用关键字async/await就可以轻松实现,在此之前需要用到委托/回调等一堆东西. 对一下是对比写法: 1 class Program 2 { 3 delegate string ...
- 【转载】 C# 中的Async 和 Await 的用法详解
众所周知C#提供Async和Await关键字来实现异步编程.在本文中,我们将共同探讨并介绍什么是Async 和 Await,以及如何在C#中使用Async 和 Await. 同样本文的内容也大多是翻译 ...
- async/await的实质理解
async/await关键字能帮助开发者更容易地编写异步代码.但不少开发者对于这两个关键字的使用比较困惑,不知道该怎么使用.本文就async/await的实质作简单描述,以便大家能更清楚理解. 一.a ...
最新文章
- Tips/Tricks#0:母版页中对控件ID的处理
- MATLAB实战系列(四)-导入txt文件技巧大全
- QT的QBrush类的使用
- 游戏安全有多重要?——GAME-TECH游戏开发者技术沙龙
- 训练集样本不平衡问题对CNN的影响
- javaScript一种优化模式-初始化时分支
- screw ---- 数据库转文档
- u盘读写测试_aigo U395固态U盘评测,速度可能会吓到你,价格很良心
- 如何批量将多个 PDF 文档转为 XPS 格式
- php的表达爱意的一句代码,表达爱意的诗句15个字
- word_excel_office向程序发送命令时出现问题
- 笔记本电脑的计算机名称在哪里看,如何查看笔记本电脑的IP地址
- contiki 操作教程
- 2022-7 刷题记录
- 群晖服务器主板维修,没那么复杂 群晖DS213j内部拆解
- Qt的.pro文件简介
- 全面解读居住证积分新政,赶紧看看你离落户上海还有多远!
- 日均调用量超13亿次,阿里达摩院研发全球首个实时翻译直播-1
- L*MM 文件管理器小结
- CSDN文本MD编辑器教程【始终专一MD】
热门文章
- 在Linux上按大小列出文件和目录
- 『中级篇』Dockerfile详解(17)
- 免杀新姿势:利用线程将恶意代码注入到内存中
- 4. MyBatis几个可以优化的地方
- 黄聪:Microsoft Enterprise Library 5.0 系列教程(四) Logging Application Block
- 腾讯急招多名.NET Core,5年30k!
- 使用Spectre.Console创建漂亮的控制台应用程序
- 使用.NET5、Blazor和Electron.NET构建跨平台桌面应用
- 十个现象,识别程序员的“水份”
- 杀鸡焉用牛刀!放下Windbg,让dotnet-stack来快速定位死锁原因