在过去的几年中,异步编程引起了很多关注,这有两个关键原因: 首先,它通过不阻塞UI线程来帮助提供更好的用户体验,从而避免了UI屏幕的挂起,直到处理完成; 第二,它有助于大幅扩展系统,而无需添加任何额外的硬件。
但是,编写异步代码并优雅地管理线程是一项繁琐的任务。但由于好处是巨大的,许多新技术和旧技术已经开始拥抱它。微软也在这方面投入了大量资金。NET 4.0,然后在。NET 4.5,他们使它比以往任何时候都更简单,引入async和await关键字。
然而,异步从一开始就可以在ASP.NET中使用,但从未得到必要的关注。考虑到ASP.NET和IIS处理请求的方式,异步可能会更有利,我们可以轻松地大幅扩展ASP.NET应用程序。随着新的编程结构的引入,如异步等待,现在是我们开始利用异步编程的强大功能的时候了。
在这篇文章中,我们将讨论IIS和ASP.NET处理请求的方式,然后我们将看到可以在ASP.NET中引入异步的地方,并讨论可以从中获得最大收益的各种方案。
如何处理请求?
每个ASP.NET请求都必须通过IIS,然后最终由ASP.NET处理程序处理。请求首先由IIS接收,并在初始处理后,转发到实际处理请求 (对于ASP.NET请求) 并生成响应的ASP.NET。然后通过IIS将此响应发送回客户端。IIS有一些工作线程,负责从队列中获取请求并执行IIS模块,然后将请求转发到ASP.NET队列。ASP.NET不会创建任何螺纹或者拥有任何线程池来处理请求,而是使用CLR线程池并从那里获取线程来处理请求。IIS模块调用ThreadPool.QueueUserWorkItem,它将请求排队到CLR工作线程。正如我们所知,CLR线程池由CLR管理和自我调整 (这意味着它根据需要创建/销毁线程)。此外,我们应该记住,创建和销毁线程始终是一项繁重的任务,这就是为什么这个池允许我们在多个任务中重用同一个线程。因此,让我们以图片方式查看请求的处理方式。
在上面的pic中,我们可以看到一个请求首先被HTTP.sys接收,并在内核级别添加到相应应用程序池的队列中。一个IIS工作线程从队列中获取请求,并在处理后将其传递给ASP.NET队列。如果不是ASP.NET请求,则该请求可能会从IIS本身返回。CLR线程池中的线程被分配给负责处理请求的线程。
什么时候应该异步用于ASP.NET?
,任何请求都可以大致分为两种类型:
CPU绑定1-
2
的I/O绑定
CPU绑定的请求需要CPU时间,并且在同一进程中执行,而I/O绑定的请求本质上是阻塞的,并且从属在执行I/O操作并返回响应的其他模块上。阻塞请求是高可扩展应用程序的主要障碍之一,在我们的大多数web应用程序中,我们在等待I/O操作时浪费了大量时间。以下是应使用异步的场景:
1-,适用于I/O绑定请求,包括
a. 的数据库访问
b.
读/写文件
Web服务调用c.
d.
访问网络资源
2
的事件驱动请求,如SignalR
3-
,在那里我们需要从多个来源获取数据
让我们创建一个示例,我们将创建一个简单的同步页面,然后将其转换为异步页面。对于这个例子,我已经把1000毫秒的延迟 (模仿一些沉重的调用,如数据库/web服务调用等),也下载了一个页面使用WebClient如下:
受 void Page_Load( 对象发件人, EventArgs e) {System.Threading.螺纹睡眠 (1000); WebClient client = WebClient的新 ();字符串downloadedContent = client.DownloadString (” https://msdn.microsoft.com/en-us/library/hh873175 % 28v = vs.110% 29.aspx”); dvcontainer.InnerHtml = downloadedContent; }
现在我们将此页面转换为异步页面。这里主要涉及三个步骤
1.通过添加将其更改为异步页面异步= true在页面指令中,如下所示:
<%@ 第页 语言= “C #” AutoEventWireup= “true” 代码隐藏= “Home.aspx.cs” 继承= “AsyncTest.Home” 异步= “true” AsyncTimeout= “3000” <span style="background-color:# ffff00;font-size:9.5pt;">%>
我还添加了AsyncTimeout (这是可选的),但我们可以根据我们的要求定义。
2.将该方法转换为异步方法。在这里,我们转换线程。睡眠和client.DownloadString到异步方法,如下所示:
私人 异步 任务AsyncWork() {等待 任务.Delay(1000); WebClient client = WebClient的新 ();字符串下载内容 =等待client.DownloadStringTaskAsync (” https://msdn.microsoft.com/en-us/library/hh873175 % 28v = vs.110% 29.aspx”); dvcontainer.InnerHtml = downloadedContent;
}
3.现在我们可以直接在Page_Load上调用此方法,并使其异步,如下所示:
受 异步 无效Page_Load( 对象发件人, EventArgs e) { 等待AsyncWork();
}
但在这里Page_Load返回的类型是异步无效,应避免在几乎所有情况下。我们知道页面生命周期的流程,Page_Load是生命周期的一部分,如果我们将其设置为异步然后可能会有场景和其他事件,即使页面加载仍在运行,生命周期也可能会被执行。强烈建议我们使用RegisterAsyncTask它允许我们注册在生命周期中执行的异步方法,而这是最合适的,并避免任何问题。所以我们应该写如下:
受 void Page_Load( 对象发件人, EventArgs e) { RegisterAsyncTask (新 PageAsyncTask) (AsyncWork));
}
现在我们已经转换了我们的页面为异步,它不会是一个阻塞请求。
我在IIS 8.5上部署了这两个应用程序,并使用突发负载进行了测试。对于相同的机器配置,同步页面能够在2-3秒内处理1,000个请求,而异步页面能够处理2,200个以上的请求。之后,我们开始收到超时或服务器不可用错误。虽然平均请求处理时间没有太大的不同,但我们能够通过使页面异步来处理超过2倍的请求。如果这不是证明我们应该利用异步编程的力量,我不知道是什么!
,还有一些其他的地方,我们可以引入异步在ASP.NET太:
1- 通过编写异步模块进行
2- 通过使用IHttpAsyncHandler或HttpTaskAsyncHandler编写异步HTTP处理程序进行
3- 使用web套接字或SignalR的
结论
在这篇文章中,我们讨论了异步编程,并看到在新的async和await关键字的帮助下,编写异步代码非常容易。我们讨论了IIS和ASP.NET处理请求的主题,并讨论了异步可以更有效的方案,我们还创建了一个简单的示例,并讨论了异步页面的好处。最后,我们探讨了ASP.NET中可以利用异步的一些地方。
感谢您的阅读!
Infragistics终极15.2在这里。下载看到它的力量在行动!
</p