ASP.NET:性能与缓存 转帖 张逸老师(http://www.cnblogs.com/wayfarer/articles/48347.aspx)
在MSDN网络课堂中下载了一些九月份的网络讲座。有很多还是很有意义的。《ASP.NET系列讲座之一:性能与缓存》是由微软开发工具专家王立楠讲授。王先生的讲解非常清晰,课件也很详细,虽然是网络讲座,但Down下来的视频文件声音很清晰。仔细听了一遍,把其中的某些要点记录了下来。
此讲主要是介绍了一些tip,以提高ASP.NET的性能。以下就是讲座介绍的一些技巧:
一、避免不必要的执行操作
Page_Load和IsPostBack
在ASP.NET中,用户每次点击页面,包括点击页面上的控件,都会激发Page_Load事件。例如如下代码:
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
先抛开Page_Load事件中的if语句不管。在用户点击页面时,会执行Page_Load中的代码,它实现了查询数据表并将结果放到DataGrid中的功能。同时,我们在Button的Click方法中也实现了查询数据表并返回结果的功能,只是查询的数据表和条件略有不同。如果没有if语句,那么当用户单击Button时,它会先执行Page_Load,然后再响应Button的Click事件。显然此时执行Page_Load是没有必要的。为什么会这样呢?因为HTTP协议是瞬时断开的。只要数据传输完毕,HTTP协议就会断开浏览器和服务器的连接。每当用户做出新的操作时,如单击页面上的Button,又会重新连接页面,此时必然会响应Page_Load事件。
因此,我们需要在Page_Load中判断Page.IsPostBack的属性。该属性指示该页是否正为响应客户端回发而加载,或者它是否正被首次加载和访问。如果是首次加载,则为false;否则为true。所以这里的Page_Load代码表达的含义是:如果页面被首次加载,则执行if里面的代码;否则忽略。因此,当用户单击Button时,由于页面之前已经被加载,所以会跳过Page_Load里的代码,这就大大地提升了ASP.NET的性能。
二、关闭不必要的Session状态
ASP.NET使用Session来保存用户的相关信息,这些信息是保存在服务器端的。Session主要与客户授权相关。如果提供了Session状态,当每次调用页面时,都会首先查询Session状态,这必然影响了页面执行的性能。因此,如果你提供的只是普通的页面,和客户授权无关,应该关闭Session状态。也许有人认为页面的Session状态影响的性能是很微小的,几乎可以忽略不计。然而试想你要做的项目涉及到的页面非常之多,每次查询Session所耗费的时间,累计起来,对性能的影响仍然是可观的。关闭Session状态的方法是在ASP.NET的html代码中设置:
<%@ Page EnableSessionState="false" %>
三、谨慎使用Server Control
1、不必要时可以不使用Server Control
在ASP.NET中提供了两种控件:Server Control和标准的HTML控件。HTML控件只响应客户端事件,而Server Control提供了RunAtServer属性,它会在服务器端建立对象的映射。它的功能比HTML控件更强大,但会损耗一定的性能。因此,在设计页面时,应根据实际的情况选择控件。如果只需要响应客户端事件,那么最好选择HTML控件,这会大大提高ASP.NET的性能。
2、不必要时可以关闭Server Control的ViewState
ViewState与Session、Application一样记录的都是ASP.NET中的状态。但ViewState作用的范围只限于页面。对于相同用户相同页面,控件的ViewState是相同的。由于控件可能会用到不同的页面中,Server Control通过ViewState来记录不同的数据状态。
但是并非所有的Server Control都需要ViewState。例如一个DataGrid控件,如果我们只是将DataSet填充到该控件中,并不对其中的数据进行操作,就不需要设置ViewState。由于ASP.NET中是将Server Control的ViewState默认设置为true,因此我们需要对控件进行重新设置:
<asp:datagrid EnableViewState="false“ runat="server"/>
如果要禁止页面所有Server Control的ViewState,则使用:
<%@ Page EnableViewState="false" %>
四、不要用Exception控制程序流程
捕获异常对性能的损耗是众所周知的。因此能够避免Exception,最好不用。例如:
try {
result = 100 / num;
}
catch (Exception e) {
result = 0;
}
上面的代码会捕获除数为0的异常。此时,完全可以用if语句来控制程序流程:
if (num != 0)
{
result = 100 / num;
}
else
{
result = 0;
}
五、禁用VB和JScript动态数据类型
在ASP.NET中,为了保持对ASP的兼容,保留了VB和JScript的动态数据类型。但在C#和VB.NET中,是不能使用动态数据类型的。由于使用动态数据类型会大量的占用运行时CPU,因此会影响到程序的性能,因此建议关闭VB和JScript动态数据类型,方法是:
<%@ Page Language="VB" Strict="true" %>
六、其它提高性能的技巧
1、使用存储过程数据访问
2、只读数据访问不要使用DataSet,而是使用SqlDataReader代替DataSet,因为SqlDataReader是read-only, forward-only
3、关闭ASP.NET的Debug模式
《ASP.NET系列讲座之一:性能与缓存》讲座还提到了通过缓存的设置来提高ASP.NET的性能。设置缓冲的方法是:
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
它主要有两个参数:Duration和VaryByParam
Duration:设置页面或控件进行缓存的时间(单位:秒)。例如我要设置缓存为60秒内有效,我就可以这样设置:
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
设置Cache有什么好处呢?举个简单的例子,你想通过网页查询某些数据,而这些数据并非实时变化,或者变化的时间是有期限的,例如查询气温。我们没有必要了解每秒每刻的气温,只需要知道当天的气温就OK了。那么我在午时一点钟和在一点过一分钟的时候去查询的气温应该完全一致。如果不设置缓存,哪怕你查询的数据完全一致,ASP.NET也会根据你的需要重复查询两次,这就增加了不必要的开销。
如果设置了缓存,只要没有过Duration所设置的期限,那么ASP.NET就直接在缓存里查询即可。
通过ACT(Application Center Test)的测试,发现设置缓存后执行的性能比未设置缓存时的性能足足提高了三倍多。
可能大家已经看到了在上面的代码中,我们将”VaryByParam“设置为none,这个参数又有什么用了。还是举刚才那个例子。我们通过城市名来查询当地的气温。例如输入“beijing”,获得的气温是27。获得的值会放入到缓存中。然而我们在60秒内,接着输入“shanghai”,因为设置缓存的原因,获取的并非shanghai的气温,而是之前放入到缓存中的beijing的气温27。
解决的办法就是使用VaryByParam。通过它可以根据设置的参数值建立不同的缓存。如果我们输入的城市名是在一个TextBox中,且该控件的ID为”txtCity”,那么我们可以将其设置到VaryByParam中:
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
此时,当我们输入“beijing”时,存储到缓存的是beijing的值。如果再60秒内输入其它城市,例如“shanghai”,它会在缓存中查询是否有参数值为“shanghai”的缓存值,如果没有去重新获得,否则读出相应的值。这样就可以避免上面所说的错误结果。
上面所述的缓冲实际上是页面缓冲,也就是说,这个缓冲是针对整个页面而言的。在ASP.NET中还有一种称为“片断缓冲”。缓冲的作用域是在UserControl中。
在ASP.NET中,提供了UserControl这种用户控件的功能。一个页面可以通过多个UserControl来组成。如果只需要在某个或某几个UserControl里设置缓存。那么可以在UserControl的Html代码中添加语句:
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
当然在UserControl中也仍然存在缓存值重复的问题。这个时候可以使用VaryByControl参数来进行设置。这个设置相当于将缓存按照UserControl进行分区。方法与设置VaryByParam相似。