(翻译)异步编程:Async/Await在ASP.NET中的介绍

8 篇文章 1 订阅
6 篇文章 0 订阅

本文翻译自:Async Programming - Introduction to Async/Await on ASP.NET | Microsoft Docs

下面翻译的内容以第一人称进行,由于翻译作者水平有限,有不对的地方请指正

        网上很多的教程围绕async/await展开的内容都是以开发客户端应用程序为主。能在Server端中使用async吗?答案是肯定的。本文介绍ASP.NET异步请求相关概念以及对应网络资源的参考链接。本文我不会涉及 async或await的语法,因为我已经写过相关的博客:Async and Await 以及文章:Async/Await - Best Practices in Asynchronous Programming | Microsoft Docs  。本文以介绍async如何在ASP.NET上工作为主。

       对于客户端应用( Windows Store, Windows desktop and Windows Phone apps),使用async是为了保证UI的实时响应。对于服务端应用,使用async的好处是scalability(译注:直白翻译是可扩展性,根据上下文推测,scalability可理解为线程可复用性)。Node.js保证scalability的关键是内置的异步特性;.NET的开放Web接口(OWIN)被设计为异步的;ASP.NET也可以设计为异步的,不单单是UI应用。

同步请求VS异步请求

       在讲解ASP.NET的Web异步请求处理方式前,让我们先了解一下ASP.NET的Web同步请求的工作方式。例如,当我们向系统请求 database或者Web Api等外部资源时,ASP.NET从线程池中取出一个线程并分配给它,因为是同步方式,请求外部资源也是同步的,线程会被阻塞直到外部调用资源有返回。图1阐述了线程池中有两个线程,其中一个被阻塞等待外部资源返回。

                                                               图1   同步等待外部资源

最后,直到外部资源调用返回,线程继续执行该请求。当请求处理完毕和返回给客户端的准备工作完成了,该线程才会回到线程池中(译注:说白了,请求外部资源时,线程一直在等待返回,白白浪费了线程资源)。

线程数量不多时,能很好地工作,但当请求数量大于ASP.NET server能提供的线程数时,就会有请求需要等待可用的线程来处理请求,图2阐述了server同样只有两个线程的线程池,当它收到了客户端发来的3个请求。

                                                     图2   只有两个线程的Server收到3个请求

在这种情况下,前两个请求从线程池中分配到线程,每个线程都请求外部资源并堵塞它们的线程。第3个请求没有可能的线程来处理请求,但它的请求已经达到Server端的系统中了,它的请求时间已经开始计算了,这样很容易得到Http 503请求错误(服务不可用)

请思考这种情况,第三个请求一直等待可用的线程,而另外两个线程事实上啥也不干,它们阻塞并等待外部资源返回。它们不在运行态并不分配CPU时间片,当有其它请求过来时,它们就白白浪费了。这种解决方案是使用异步请求。

异步请求处理和同步请求不同,当一个请求过来时,ASP.NET从线程池中取出一个线程来处理请求,这时请求外部资源是异步的,这时,线程会返回到线程池中,图3阐述了只有两个线程的线程池异步处理等待外部资源的工作方式:

                                                                 图3   异步等待外部资源

最大的不同是,当请求外部资源时,线程已经返回到线程池中了,已经和请求没有任何的联系了。这时,当外部资源返回时,ASP.NET会从线程池中重新分配一个线程给请求,该线程继续往下执行该请求。当请求完毕后,该线程回到线程池中。注意:同一个线程在同步请求的整个生命周期,相反,异步编程,不同的线程分配到同一个请求(在不同时间点)。

这时,当有3个请求过来时,服务端可以处理它们,因为线程已经回到线程池了尽管请求还有异步外部资源需要等待。只要线程池中有空闲的线程,就可以处理新的请求。异步请求使得小量的线程可以请求相对大量的请求。所以ASP.NET的异步代码的优点是scalability(可拓展)。

为何不增加线程池的数量?

为何不增加线程池的大小这个问题经常有人问。答案分两个方面:与阻塞线程池线程相比,异步代码可以进一步扩展,速度也更快。

异步代码可以进一步扩展是因为比阻塞线程使用更小的内存,每个线程需要操作系统分配1MB的堆栈,加上一个不可分页的内核堆栈。这听起来不是很多,但真正当你启动很多线程的时候,你就会发现问题了。所以,异步请求处理比阻塞线程请求内存压力更少。异步代码使得有更多的内存去处理其他事情(如缓存)。

         异步代码的拓展速度比阻塞线程更快,因为线程池的线程注入速度受限。在写本文时,速度是一个线程需要两秒。线程注入受限的优点是它避免了同一个线程重复构建或者销毁。考虑到突然有大量的请求涌进来时,当请求使用完所有可用线程时,同步代码很容易有问题,因为剩下的请求只能等待新的线程注入到线程池中。而异步代码会更好地处理突发的大请求量。

后面的不是很感兴趣了,就不翻译了,有兴趣的老铁可以去看看原文。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值