在衡量应用程序的性能时,您是否考虑以下几点?
- 缓存
- 无会话控制器
- 异步控制器
输出缓存:
也许 MVC3( Performance-Wise )最有用的特性是输出缓存。当您的应用程序确实必须获取数据、对其进行计算并返回数据时,实际上会发生最大的性能损失。输出缓存可以缓存这些结果,因此它们可以直接返回,甚至无需接触数据库。尤其是在执行复杂查询时,这可以显着降低服务器上的负载(实际上,通过在 Web 应用程序中仔细实现缓存,您可以将服务器上的负载降低 90%)。
namespace MvcApplication1.Controllers
{
public class DataController : Controller
{
[OutputCache(Duration=10)]
public string Index()
{
return DateTime.Now.ToString("T");
}
}
}
无会话控制器:
禁用会话状态的控制器为不需要会话状态的控制器提供了优化。无状态控制器适用于不需要会话概念的情况。
默认情况下,ASP.NET 管道不会同时处理属于同一会话的请求。它对它们进行序列化,即按照它们被接收的顺序对它们进行排队,以便它们被串行处理而不是并行处理。这意味着如果一个请求正在进行中并且来自同一会话的另一个请求到达,它将排队等待仅在第一个请求完成时才开始执行。
让我们看一个例子;向服务器发出 3 个异步 AJAX 请求的页面,启用了会话状态(另请注意,必须实际使用会话,因为 ASP.NET 足够聪明,即使您从不使用会话状态,也不会序列化请求,即使它已启用)。
jQuery
$(document).ready(function () {
//Make 3 concurrent requests to /ajaxtest/test
for (var i = 0; i < 3; i++) {
$.post("/ajaxtest/test/" + i,
function (data) {
//Do something with data...
},
"json");
}
});
控制器 - 动作方法
public class AjaxTestController : Controller
{
[HttpPost]
public JsonResult Test(int? id)
{
Thread.Sleep(500);
return Json(/*Some object*/);
}
}
![在此处输入图像描述](https://i.stack.imgur.com/hVLIQ.png)
可以在网络配置文件中看到序列化请求的效果;每个请求比前一个请求花费大约 500 毫秒。所以这意味着我们没有从异步进行这些 AJAX 调用中获得任何好处。让我们再次查看为我们的 AjaxTestController 禁用会话状态的配置文件(使用 [SessionState] 属性)。
[SessionState(SessionStateBehavior.Disabled)]
public class AjaxTestController : Controller
{
//...As above
}
![在此处输入图像描述](https://i.stack.imgur.com/2aaXT.png)
好多了!您可以看到 3 个请求是如何并行处理的,总共需要 500 毫秒才能完成,而不是我们在第一个示例中看到的 1500 毫秒。
异步控制器:
首先,控制器开始一个或多个外部 I/O 调用(例如,SQL 数据库调用或 Web 服务调用)。无需等待它们完成,它就会将线程释放回 ASP.NET 工作线程池,以便它可以处理其他请求。
稍后,当所有外部 I/O 调用完成时,底层 ASP.NET 平台从池中获取另一个空闲工作线程,将其重新附加到您的原始 HTTP 上下文,并让它完成对原始请求的处理。
![在此处输入图像描述](https://i.stack.imgur.com/GLy30.png)
我从此链接复制了以下内容。因为有时链接会被破坏所以我在这里保留了一些重要的部分。请检查此链接以获取更多详细信息
要了解异步控制器如何响应不同级别的流量,以及这与简单的同步控制器相比有何不同,您可以创建一个包含两个控制器的示例 MVC。为了模拟长时间运行的外部,它们都执行了一个需要 2 秒才能完成的 SQL 查询(使用 SQL 命令 WAITFOR DELAY '00:00:02'),然后它们将相同的固定文本返回给浏览器。其中一个同步执行;另一个异步。
在另一个示例中,您可以检查一个简单的 C# 控制台应用程序,该应用程序模拟了访问给定 URL 的大量流量。它只是一遍又一遍地请求相同的 URL,计算最后几个响应时间的滚动平均值。首先它只在一个线程上执行此操作,但随后在 30 分钟内逐渐将并发线程数增加到 150 个。如果您想尝试在您自己的网站上运行此工具,您可以下载 C# 源代码。
结果说明了有关异步请求如何执行的一些要点。查看这张平均响应时间与并发请求数的关系图(响应时间越短越好):
![在此处输入图像描述](https://i.stack.imgur.com/ZQ4XH.png)
要理解这一点,首先我需要告诉您,我已将 ASP.NET MVC 应用程序的工作线程池人为地设置为 50 个工作线程的最大限制。我的服务器实际上有一个默认的最大线程池大小为 200——一个更合理的限制——但如果我减少它,结果会更清楚。如您所见,只要有足够的工作线程可以运行,同步和异步请求的执行完全相同。他们为什么不应该呢?但是一旦线程池用完(> 50 个客户端),同步请求必须形成一个队列来提供服务。基本排队理论告诉我们,在队列中等待的平均时间由以下公式给出:
![在此处输入图像描述](https://i.stack.imgur.com/Ksxij.png)
这正是我们在图中看到的。排队时间随队列长度线性增长。(为我沉迷于使用公式而道歉——有时我就是无法抑制我内心的数学家。如果它成为问题,我会接受治疗。)不过,异步请求不需要这么快就开始排队。他们不需要在等待时阻塞工作线程,因此线程池限制不是问题。那么为什么当有超过 100 个客户时他们开始排队呢?这是因为 ADO.NET 连接池默认限制为 100 个并发连接。
希望这对您有所帮助。