首页 > 编程 > .NET > 正文

ASP.NET 谨用 async/await

2024-07-10 12:48:53
字体:
来源:转载
供稿:网友

C# 5.0 引入 async/await 关键字,旨在简化异步编程模型,抛去语法糖就是 Net4.0 的 Task + 状态机。其实在处理异步编程使用 Task 还是挺简单的,不过既然推出了新的语法糖,难免会尝试一下,然而在使用中却没想象中那么单纯。以下针对ASP.NET 应用程序实际使用过程中的一些总结, 包括 异常捕获 、 死锁 、 应用程序崩溃 ,实际使用过程中一不注意就可能掉坑里了。

异常捕获

async 方法有三种返回类型: void、Task、Task

async void

该方式声明的方法是无法使用 catch 捕获异常的,所以以下代码的 try、catch 并没什么卵用。

private static async void ThrowExceptionAsync(){ await Task.Delay(1000); throw new Exception("抛个异常玩玩");}public static async void CatchAsyncVoidException(){ try {  ThrowExceptionAsync(); } catch (Exception ex) { throw ex; }}

async Task 或 async Task

这两种方式声明的方法异常信息会包含Task属性内,但前提需要在try里面使用 await 等待。

private static async Task ThrowExceptionAsync(){ await Task.Delay(1000); throw new Exception("抛个异常玩玩");}public static async Task CatchAsyncTaskException(){ try {   await ThrowExceptionAsync(); } catch (Exception ex) { throw ex; }}TaskScheduler.UnobservedTaskException

未捕获的 Task 异常信息可以通过设置全局的TaskScheduler.UnobservedTaskException 来记录错误日志,在 Global.asax 增加如下代码:

void Application_Start(object sender, EventArgs e){ // 在应用程序启动时运行的代码 TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskExceptionException;}void TaskScheduler_UnobservedTaskExceptionException(object sender, UnobservedTaskExceptionEventArgs e){ if (e.Exception != null) { // do something }}

同步上下文

异步编程必然是关于线程的使用,线程有一个同步上下文的概念,个人认为线程同步上下文是 async/await 遇到最揪心的问题。在现有项目开发中我们可能想尝试使用 async/await,但老代码都是同步方式,这时如果调用一个声明为 async 的方法,死锁和应用程序崩溃的问题一不小心就可能出现。

注意:控制台程序和.Net Core程序 将不会遇到这个问题,它们不需要同步上下文。

死锁

private static async Task XXXAsync(){ await Task.Delay(1000);  // some code}public static void Test(){ var task = XXXAsync(); task.Wait();}

以上代码很完美的实现了死锁。 默认情况下,当 Wait() 未完成的 Task 时,会捕获当前线程上下文,在 Task 完成时使用该上下文恢复方法的执行。 当 async 方法内的 await 执行完成时,它会尝试获取调用者线程所在的上下文执行方法的剩余部分, 但是该上下文已含有一个线程,该线程在等待 async 方法完成。然后它们相互等待对方,然后就没有然后了,死在那里。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表