• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >ASP.NET > ASP.NET 谨用 async/await

ASP.NET 谨用 async/await

作者:Beck''s Blog 字体:[增加 减小] 来源:互联网 时间:2018-08-20

Beck''s Blog 通过本文主要向大家介绍了asp.net,async,await等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

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 方法完成。然后它们相互等待对方,然后就没有然后了,死在那里。

针对死锁问题的解决方式是增加 ConfigureAwait(false)

// await Task.Delay(1000);
await Task.Delay(1000).ConfigureAwait(false); // 解决死锁

当 await 等待完成时,它会尝试在线程池上下文中执行 async 方法的剩余部分,因此就不存在死锁。

应用程序崩溃

测试环境总发现IIS应用程序池总是崩溃,到底是什么原因?当时我们对这个问题也是非常懵逼,代码看上去并没什么明显毛病,试图欺骗自己应该是环境本身的问题吧,但事实上确实是在代码中下了毒。通过各种资料查阅和测试,基本可以断定是同步代码调用异步代码,同步上下文引起的问题。

如果调用一个 async 方法。如果使用 await 等待,当前线程立马被释放回线程池,线程的上下文信息会被保存。如果没有使用 await(async void 的方法,必然没有办法使用 await),调用 async 方法之后,代码会继续往下执行,执行完成后当前线程被释放回线程池,线程的上下文信息不会被保存。当 async 中的异步任务执行完成后,会从线程池中获取一个线程继续执行剩余代码,同时会获取当初调用者所在线程的上下文信息(如果当初调用者所在线程没有释放回线程池,上下文信息可以获取到)。那么问题就来了,如果当初调用者没有使用 await 并且 所在线程释放回线程池了,上下文信息因为没有被保持下来,就获取不到了,这时候会抛出异常 未将对象引用设置到对象的实例 ,经过测试这个异常信息并不一定每次都会出现,原因和线程的释放有关,调用者所在线程的上下文信息存在就不会抛出异常。异常错误信息如下,这个异常最终会导致应用程序集停止。

在 System.Web.ThreadContext.AssociateWithCurrentThread(Boolean setImpersonationContext)
  在 System.Web.HttpApplication.OnThreadEnterPrivate(Boolean setImpersonationContext)
  在 System.Web.LegacyAspNetSynchronizationContext.CallCallbackPossiblyUnderLock(SendOrPostCallback callback, Object state)
  在 System.Web.LegacyAspNetSynchronizationContext.CallCallback(SendOrPostCallback callback, Object state)
  在 System.Web.LegacyAspNetSynchronizationContext.Post(SendOrPostCallback callback, Object state)
  在 System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.PostAction(Object state)
  在 System.Threading.Tasks.AwaitTaskContinuation.RunCallback(ContextCallback callback, Object state, Task& currentTask)
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
  在 System.Threading.Tasks.AwaitTaskContinuation.<>c.<ThrowAsyncIfNecessary>b__18_0(Object s)
  在 System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
  在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
  在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
  在 System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
  在 System.Threading.ThreadPoolWorkQueue.Dispatch()
  在 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

针对以上异常我们有什么方式可以解决呢?依然是ConfigureAwait(false),在 Task 上加上 ConfigureAwait(false),此设置代表当 async 中的异步任务完成后,不读取当时调用它的原线程的上下文信息,而是在线程池上下文中执行 async 方法的剩余部分。

public static Task XXXAsync()
{
 await Task.Run(() =>
 {
 // some code
 }).ConfigureAwait(false);
}

总结

以上所述是小编给大家介绍的ASP.NET 谨用 async/await,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Asp.net SignalR 应用并实现群聊功能 开源代码
  • asp.net动态更新
  • asp.net利用母版制作页脚效果
  • Asp.Net服务器发送HTTP标头后无法设置内容类型的问题解决
  • 使用asp.net mvc,boostrap及knockout.js开发微信自定义菜单编辑工具(推荐)
  • 详解ASP.NET MVC 常用扩展点:过滤器、模型绑定
  • ASP.NET Core发送邮件的方法
  • 在ASP.NET Core 中发送邮件的实现方法(必看篇)
  • ASP.NET MVC从视图传参到控制器的几种形式
  • Asp.net core WebApi 使用Swagger生成帮助页实例

相关文章

  • 2017-05-11ASP.NET中高质量缩略图的生成代码
  • 2017-05-11ASP.NET访问共享文件夹的详细步骤
  • 2018-08-20.Net Web Api中利用FluentValidate进行参数验证的方法
  • 2017-05-11asp.net使用DataTable构造Json字符串的方法
  • 2017-05-11google suggest 下拉菜单实现代码(asp.net版本)
  • 2017-05-11微信公众平台开发之语音识别.Net代码解析
  • 2018-08-20Asp.NetCore1.1版本去掉project.json后如何打包生成跨平台包
  • 2017-05-11.NET微信公众号开发之准备工作
  • 2017-05-11如何在网站级别动态更改主题
  • 2017-05-11完美解决在ModalPopupExtender中使用CalendarExtender时被层遮挡的问题

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • VS2005 水晶报表在时部署时遇到的问题
    • .aspx中的命名空间设置实现代码
    • 调试ASP.NET2005/2008时,端口不正确的解决三套方案
    • Gridview利用DataFormatString属性设置数据格式的方法
    • ASP.NET实现个人信息注册页面并跳转显示
    • ASP.NET对路径"xxxxx"的访问被拒绝的解决方法小结
    • 当年学习ADO.NET的笔记
    • C# 小数位数保留的方法集锦
    • ASP.NET 小技巧(2个)
    • C# javaScript函数的相互调用

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有