ASP.Net中的async+await异步编程的实现_实用技巧

来源:脚本之家  责任编辑:小易  

使用异步编程,可以避免2113性能瓶颈并5261增强应用程序的总4102体响应能力。 但是,编写异步应用程序的1653传统技术可能比较复杂,使它们难以编写、调试和维护。C# 中的 async 和 await 关键字都是异步编程的核心。 通过使用这两个关键字,可以使用 .NET framework 或 Windows 运行时中的资源轻松创建异步方法(几乎与创建同步方法一样轻松)。 通过使用被称为异步方法的 async 和 await 定义的异步方法。特征:方法签名包含一个 Async 或 async 修饰符。按照约定,异步方法的名称以“Async”后缀结尾。返回类型为下列类型之一:如果你的方法有操作数为 TResult 类型的返回语句,则为 Task<TResult>。如果你的方法没有返回语句或具有没有操作数的返回语句,则为 Task。方法通常包含至少一个 await 表达式,该表达式标记一个点,在该点上,直到等待的异步操作完成方法才能继续。 同时,将方法挂起,并且控件返回到方法的调用方。 本主题的下一节将解释悬挂点发生的情况。在异步方法中,可使用提供的关键字和类型来指示需要完成的操作,且编译器会完成其余操作,其中包括持续跟踪控件以挂起方法返回等待点时发生的情况。 一些常规流程(例如,循环和异常处理)在传统异步代码中处理起来可能很困难。 在异步方法中,元素的编写频率与同步解决方案相同且此问题得到解决www.zgxue.com防采集请勿采集本网。

在.NET Framework4.5框架、C#5.0语法中,通过async和await两个关键字,引入了一种新的基于任务的异步编程模型(TAP)。在这种方式下,可以通过类似同步方式编写异步代码,极大简化了异步编程模型。

同步的概念:执行一个方法或者功能,在没得到结果前,其他方法不执行,一定得等当前方法执行完,才会执行下一步骤 异步的概念:执行一个方法或者功能,不需要等待到当前方法执行完,其他方法也可以执行 一. Javascript异步编程 Javascript是单线

用法:

是因为这些操作还是被派给了UI线程来执行。 await可以被理解成.NET 4中的CallBack:当任务结束后会触发一个完成事件。使用await的目的是await标记的代码在完成事件被触发以后再执行。应该不会影响到UI的卡与不卡。 试着把LetFeedShowAsync(int i

public async Task<int> GetDotNetCountAsync(){ // Suspends GetDotNetCount() to allow the caller (the web server) // to accept another request, rather than blocking on this one. var html = await _httpClient.GetStringAsync("https://dotnetfoundation.org"); return Regex.Matches(html, @"\.NET").Count;}

要点!!!

1.“async”用来标记一个方法为异步方法,异步方法体内需结合“await”关键字使用,如果没有await,则该方法等同于一个普通方法。异步方法命名规则通常以Async结尾。

2.“await”关键字只能在异步方法中使用。

3.当在async异步方法中遇到await操作时,await会阻塞该异步方法不继续往下执行,并将该异步方挂起,将控制权转到该异步方法的调用者手中。

4.异步方法的调用者获得控制权之后:

1)如果调用者需要使用异步方法的返回结果,则继续等待异步方法执行完毕,再继续往下执行。

2)如果调用者不关心异步方法的返回结果,则继续往下执行。

场景一:async方法中未使用await

static void Main(string[] args) { Console.WriteLine("执行前Main.....线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());//步骤① GetResultAsync(); Console.WriteLine("执行结束Main....线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());//步骤② Console.ReadKey(); } async static Task<int> GetResultAsync() { Console.WriteLine("执行前GetResult.....线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());//步骤③ Task.Delay(3000).Wait(); Console.WriteLine("执行结束GetResult.....线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());//步骤④ return 10; }

执行结果:步骤① ——>步骤③——>步骤④——>步骤②

结果分析:

我们会发现,主函数Main调用异步方法GetResultAsync时,由于异步方法缺少“await”关键字,主函数需等异步方法步骤3,4全部执行结束后再继续执行步骤2,执行顺序完全和同步方法执行顺序一致;

并且异步方法会给出语法提示:缺少“await”关键字

场景2:异步方法体内遇到await之后,立即将控制权转到调用者手中

static void Main(string[] args) { Console.WriteLine("执行前Main.....线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());//步骤① GetResultAsync(); Console.WriteLine("执行结束Main....线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());//步骤② Console.ReadKey(); } async static Task<int> GetResultAsync() { Console.WriteLine("执行前GetResult.....线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());//步骤③ await Task.Delay(3000); Console.WriteLine("执行结束GetResult.....线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());//步骤④ return 10; }

执行结果:步骤① ——>步骤③——>步骤②——>步骤④

结果分析:

我们会发现,主函数Main调用异步方法GetResultAsync,在遇到异步方法中“await”关键字时

1)阻塞了当前异步方法并立即将控制权转交给调用者主函数Main

2)主函数获得控制权后继续执行方法体内步骤2,GetResultAsync方法则异步执行(等待异步操作结束之后执行步骤4)。

场景3:异步方法体内遇到await之后,立即将控制权转到调用者手中,调用者需等待异步方法返回结果

static void Main(string[] args) { Console.WriteLine("执行前Main.....线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());//步骤① Task<int> res = GetResultAsync(); Console.WriteLine("执行结束Main....线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());//步骤② Console.WriteLine("执行结果:" + res.Result + "....线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());//步骤③ Console.ReadKey(); } async static Task<int> GetResultAsync() { Console.WriteLine("执行前GetResult.....线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());//步骤④ await Task.Delay(3000); Console.WriteLine("执行结束GetResult.....线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());//步骤⑤ return 10; }

执行结果:步骤① ——>步骤④——>步骤②——>步骤⑤——>步骤③

结果分析:

我们会发现,主函数Main调用异步方法GetResultAsync,在遇到异步方法中“await”关键字时

1)阻塞了当前异步方法并立即将控制权转交给调用者主函数Main

2)主函数获得控制权后继续执行方法体内步骤2和步骤3,GetResultAsync方法则异步执行。

3)当主函数执行步骤3时,由于步骤3需要打印异步方法的返回结果,故需要等待异步方法结束才能继续。所以需先执行步骤5,然后再继续执行步骤3。

最后,异步编程的时候我们通常会结合Task来使用

到此这篇关于ASP.Net中的async+await异步编程的实现的文章就介绍到这了,更多相关ASP.Net async+await异步编程内容请搜索真格学网以前的文章或继续浏览下面的相关文章希望大家以后多多支持真格学网! 您可能感兴趣的文章:ASP.NET 谨用 async/await

相对于之前2113Begin/End模式和事件模式,async/await模式让程序5261员得以用同步的代码结构进4102行异步编程。1653async/await入门很方便,但是深入理解却涉及很多领域,如线程池、同步上下文等等。我断断续续接触了几个月,稍微有一些心得:await的作用是等待异步Task完成,并不是阻塞的。举个例子,一个异步方法:public async Task Caller(){    Action0();    await Method();    Action3();}public async Task Method(){    Action1();    await Task.Delay(1000);    Action2();}A. 当你在非UI线程A上执行Caller(),将完成以下几件事:[线程A]执行Action0()[线程A]调用await Method()[线程A]执行Action1()[线程A]启动任务Task.Delay(1000),并在线程池里安插一个新任务,在Task.Delay(1000)完成后,由另一个线程执行6[线程A]去处理别的事情[线程B]执行Action2()[线程B]await Method()返回[线程B]执行Action3()    其中,线程A和线程B并不保证是同一个线程。如果你在await前后打印线程ID,你会发现ID是不同的。B. 当你在UI线程上执行Caller(),过程有了变化:[UI线程]执行Action0()[UI线程]调用await Method()[UI线程]执行Action1()[UI线程]启动任务Task.Delay(1000),并在线程池里安插一个新任务,在Task.Delay(1000)完成后,由另一个线程执行6[UI线程]去处理别的事情[线程C]在UI线程的同步上下文中执行7(类似于在窗体类上执行Invoke()方法)[UI线程]执行Action2()[UI线程]await Method()返回[UI线程]执行Action3()    可见,当使用await方法的线程为UI线程时,程序默认会通过第6步,保证await前后是同一个线程ID。这个当然是有一定性能牺牲的(甚至会造成死锁,在D里会讨论),如果你不想在await完成后回到UI线程,见C。C. 你可以在UI线程上使用await XXX().ConfigureAwait(false)去替代await XXX(),来禁止当await XXX()结束时恢复线程。举个例子,执行下列代码是没问题的(如B里描述的):private async void button1_Click(object sender, EventArgs e){    this.Text = "123";    await Task.Delay(1000);    this.Text = "321";}但是,执行下列代码就会发生“线程间操作无效”的错误:private async void button1_Click(object sender, EventArgs e){    this.Text = "123";    await Task.Delay(1000).ConfitureAwait(false);    this.Text = "321";    //线程间操作无效}因为执行this.Text = "321";的线程已经不再是UI线程。D. 顺便一提,Task.Wait()方法,相比于await Task,会同步地执行Task。但是,如果你在UI线程上Wait的Task里本身又有await,那么将会产生死锁:private void Foo(object sender, EventArgs e){    this.Text = "123";    Method().Wait();        //此处发生死锁    this.Text = "321";    //这行永远也不会执行}private async Task Method(){    await Task.Delay(1000);}    为什么呢?Method().Wait()会阻塞UI线程等待Method()完成,但是参照B过程,在await完成后,Method()完成前,是需要恢复到UI线程的,但是此时UI线程已经被阻塞了,因此死锁就发生了。    要避免这个死锁,可以参照C。E. 说出来你可能不信,上面的都是我手打的。在内容上虽然不一定严谨,但希望对楼主和其它新接触TAP的朋友有一定启发内容来自www.zgxue.com请勿采集。


  • 本文相关:
  • linq重写博客垃圾图片回收算法
  • vs2015+qt5+opencv3开发环境配置
  • asp.net mvc下使用rest的方法
  • c#后台调用前台javascript的五种方法小结
  • asp.net比较常用的26个性能优化技巧
  • asp.net连接sql2008数据库的实现代码
  • "pagemethods未定义"或"对象不支持此属性或方法&
  • mvc+easyui+三层新闻网站建立 主页布局的方法(五)
  • repeater 分列显示以及布局的实例代码
  • asp.net在事件中启动线程来打开一个页面的实现方法
  • 如何正确理解.NET 4.5和C#5.0中的async/await异步...
  • 如何正确理解.NET 4.5和C#5.0中的async/await异步...
  • 如何正确理解.NET 4.5和C#5.0中的async/await异步...
  • 如何正确理解.NET 4.5和C#5.0中的async/await异步...
  • 深刻理解异步和同步以及异步编程有哪些方式
  • [新手求助] c# 异步编程,用了await了,为什么还是...
  • 如何正确理解.NET 4.5和C#5.0中的async/await异步...
  • 网站首页网页制作脚本下载服务器操作系统网站运营平面设计媒体动画电脑基础硬件教程网络安全基础应用实用技巧自学过程首页asp.netasp.net 谨用 async/awaitlinq重写博客垃圾图片回收算法vs2015+qt5+opencv3开发环境配置asp.net mvc下使用rest的方法c#后台调用前台javascript的五种方法小结asp.net比较常用的26个性能优化技巧asp.net连接sql2008数据库的实现代码"pagemethods未定义"或"对象不支持此属性或方法&mvc+easyui+三层新闻网站建立 主页布局的方法(五)repeater 分列显示以及布局的实例代码asp.net在事件中启动线程来打开一个页面的实现方法java正则表达式 pattern和matche未将对象引用设置到对象的实例 (asp.net(c#)网页跳转七种方法小结未能加载文件或程序集“xxx”或它asp.net“服务器应用程序不可用”asp.net中的几种弹出框提示基本实asp.net gridview 72般绝技asp.net生成excel并导出下载五种asp.net对路径"xxxxx"asp.net汉字转拼音和获取汉字首字asp.net 2.0 中收集的小功能点(转)asp.net core使用graphql第二章之中间件asp.net couchbase memcached图文安装调用asp.net中水印的具体实现代码在asp.net core中实现一个token base的身.net core中使用ref和span<t>提高程让gridview只显示特定用户的数据的方法webapi2 文件图片上传与下载功能动态代理的5模式使用示例和mixin模式深入lumisoft.net组件与.net api实现邮件
    免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved