1.ASP.NET线程模型
在WEB程序中,天生就是多线程的,我们知道,一个WEB服务可以同时服务器多个用户,我们可以想象一下,WEB程序应该运行于多线程环境中,对于运行WEB程序的线程,我们可以称之为WEB线程。因为线程池最小线程数为2(可配置),紧接着后面的请求会每隔半秒钟开始一个,因为如果池中的线程都忙,会等待半秒(.NET版本不同而不同),如果还是没有线程释放则开启新的线程,直到达到最大线程数(可配置)。未能在线程池中处理的请求将被放入请求队列,当一个线程释放后,下一个请求紧接着开始在该线程处理。 当WEB线程长时间被占用时,请求会由于线程池而阻塞,同时产生大量的线程,最终响应时间变长。
2.请求是如何处理的
每个 ASP.NET 请求都要先通过 IIS,然后再由 ASP.NET 处理程序进行最终处理。 首先IIS 接收请求,初步处理后,发送给ASP.NET(必须是一个ASP.NET请求),然后由ASP.NET进行实际处理并生成响应,之后该响应通过IIS发回给客户。在IIS上,有一些工作进程负责从队列中取出请求,并执行IIS 模块,然后再将该请求发送到ASP.NET 队列。但是,ASP.NET本身不创建任何线程,也没有处理请求的线程池,而是通过使用CLR 线程池,从中获取线程来处理请求。因此,IIS 模块调用ThreadPool.QueueUserWorkItem,将请求排入队列,供CLR 工作线程处理。我们都知道,CLR线程池是由CLR管理,并且能够自动调整(也就是说,它根据需要创建和销毁进程)。这里还要记住,创建和销毁线程是项很繁重的任务,这就是为什么CLR线程池允许使用同一个线程处理多个任务。下面来看一个描述请求处理过程的图示。
请求首先由 HTTP.sys接收,并添加到相应内核级应用程序池队列。然后,一个IIS工作线程从队列中取出请求,处理后将其传到ASP.NET 队列。注意,该请求如果不是一个ASP.NET请求,将从 IIS 自动返回。最后,从CLR线程池中分配一个线程,负责处理该请求。
3.应用场景
所有请求大致可以分为两类:
1. CPU Bound 类
2. I/O Bound 类
CPU Bound 类请求,需要 CPU 时间,而且是在同一进程中执行;而 I/O Bound 类请求,本身具有阻塞性,需要依赖其他模块执行 I/O 操作并返回响应。阻塞性请求是提高应用程序可伸缩性的主要障碍,而且大多数web应用程序中,在等待 I/O 操作的过程中浪费了大量时间。 因此以下场景适合使用异步:
-
I/O Bound 类请求,包括:
a. 数据库访问
b. 读/写文件
c. Web 服务调用
d. 访问网络资源
-
事件驱动的请求,比如SignalR
-
需要从多个数据源获取数据的场景
4.异步Action(MVC)、WEBAPI、EF、ASP.NET Core
(1)NOPCommerce4.10(Net Core2.1)中Razor增加了许多异步方法:Component.InvokeAsync(异步调用具名组件)、Html.PartialAsync(异步加载分部视图,返回html格式的标签)
(2)SmartStore3.x(NetFramework4.6.1)
1.导入产品、客户等功能(将文件、图片写入磁盘功能,IO操作):异步方法, 提升系统效率。
2.SmartStore.Core.Async.AsyncRunner异步代理方法,可以代理运行各种异步方法。系统中所有异步方法都通过此方法进行调用。
5.利用 async & await 进行异步 IO 操作
https://www.cnblogs.com/liqingwen/p/6082673.html
其他:
https://blog.csdn.net/wangpeng198688/article/details/51144246
https://blog.csdn.net/taoerchun/article/details/49763437
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/using-async-for-file-access