跳至正文
首页 » 博客 » Leveraging the Power of Asynchrony in ASP.NET

Leveraging the Power of Asynchrony in ASP.NET

在过去的几年中,异步编程引起了很多关注,这有两个关键原因: 首先,它通过不阻塞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