ASP.NET程序性能优化(二)

三、c#(或vb.net)程序改进(代码改进)

1使用值类型的TOSTRING方法

在连接字符串时,经常使用"+"号直接将数字添加到字符串中这种方法虽然简单,也可以得到正确结果,但是由于涉及到不同的数据类型,数字需要通过装箱操作转化为引用类型才可以添加到字符串中但是装箱操作对性能影响较大,因为在进行这类处理时,将在托管堆中分配一个新的对象,原有的值复制到新创建的对象中


使用值类型的TOSTRING方法可以避免装箱操作,从而提高应用程序性能


INT NUM=1;
STRING STR="GO"+NUM.TOSTRING();


2运用STRINGBUILDER类


STRING类对象是不可改变的,对于STRING对象的重新赋值在本质上是重新创建了一个STRING对象并将新值赋予该对象,其方法TOSTRING对性能的提高并非很显著


在处理字符串时,最好使用STRINGBUILDER类,其.NET 命名空间是SYSTEM.TEXT该类并非创建新的对象,而是通过APPEND,REMOVE,INSERT等方法直接对字符串进行操作,通过TOSTRING方法返回操作结果


其定义及操作语句如下所示:


INT NUM;

SYSTEM.TEXT.STRINGBUILDER STR = NEW SYSTEM.TEXT.STRINGBUILDER(); //创建字符串


STR.APPEND(NUM.TOSTRING()); //添加数值
NUM

RESPONSE.WRITE(STR.TOSTRING); //显示操作结果



3使用 HTTPSERVERUTILITY.TRANSFER 方法在同一应用程序的页面间重定向


采用 SERVER.TRANSFER 语法,在页面中使用该方法可避免不必要的客户端重定向(RESPONSE.REDIRECT)


4避免使用
ARRAYLIST

因为任何对象添加到ARRAYLIST都要封箱为SYSTEM.OBJECT类型,从ARRAYLIST取出数据时,要拆箱回实际的类型建议使用自定义的集合类型代替ARRAYLISTASP 2.0提供了一个新的类型,叫泛型,这是一个强类型,使用泛型集合就可以避免了封箱和拆箱的发生,提高了性能


5使用HASHTALE代替其他字典集合类型
(如STRINGDICTIONARY,NAMEVALUECOLLECTION,HYBRIDCOLLECTION),存放少量数据的时候可以使用
HASHTABLE.

6为字符串容器声明常量,不要直接把字符封装在双引号" "里面

//避免
MYOBJECT OBJ = NEW MYOBJECT();
OBJ.STATUS = "ACTIVE";

//
推荐
CONST STRING C_STATUS = "ACTIVE";
MYOBJECT OBJ = NEW MYOBJECT();
OBJ.STATUS = C_STATUS;

7
不要用TOUPPER(),TOLOWER()转换字符串进行比较,用STRING.COMPARE代替,它可以忽略大小写进行比较
.
例:

CONST STRING C_VALUE = "COMPARE";
IF (STRING.COMPARE(SVARIABLE, C_VALUE, TRUE) == 0)
{
CONSOLE.WRITE( "
相同
");
}
也可以用STR == STRING.EMPTY或者STR.LENGTH == 0判断是否为空(注意判断输入数据的长度,可防止SQL注入式攻击
)
将STRING对象的LENGTH属性与0比较是最快的方法,避免不必要的调用 TOUPPER 或 TOLOWER 方法


8类型转化INT32.TRYPARSE()优于INT32.PARSE()优于
CONVERT.TOINT32()

建议.NET1.1下用INT32.PARSE();.NET2.0用
INT32.TRYPARSE()
因为:

CONVERT.TOINT32 会把最终的解析工作代理给 INT32.PARSE;
INT32.PARSE 会把最终的解析工作代理给NUMBER.PARSEINT32;
INT32.TRYPARSE 会把最终的解析工作代理给
NUMBER.TRYPARSEINT32

9如果只是从XML对象读取数据,用只读的XPATHDOCUMENT代替XMLDOCUMENT,可以提高性能


//避免
XMLDOCUMENT XMLD = NEW XMLDOCUMENT();
XMLD.LOADXML(SXML);
TXTNAME.TEXT = XMLD.SELECTSINGLENODE( "/PACKET/CHILD").INNERTEXT;

//
推荐
XPATHDOCUMENT XMLDCONTEXT = NEW XPATHDOCUMENT(NEW STRINGREADER(OCONTEXT.VALUE));
XPATHNAVIGATOR XNAV = XMLDCONTEXT.CREATENAVIGATOR();
XPATHNODEITERATOR XPNODEITER = XNAV.SELECT( "PACKET/CHILD");
ICOUNT = XPNODEITER.COUNT;
XPNODEITER = XNAV.SELECTDESCENDANTS(XPATHNODETYPE.ELEMENT, FALSE);
WHILE(XPNODEITER.MOVENEXT())
{
SCURRVALUES += XPNODEITER.CURRENT.VALUE+ ",";
}


10
避免在循环体里声明变量,应该在循环体外声明变量,在循环体里初始化

C#程序开发要遵循的一个基本原则就是避免不必要的对象创建

//避免
FOR(INT I=0; I<10; I++)
{
SOMECLASS OBJSC = NEW SOMECLASS();
}

//
推荐
SOMECLASS OBJSC = NULL;
FOR(INT I=0; I <10; I++)
{
OBJSC = NEW SOMECLASS();
}

11
捕获指定的异常,不要使用通用的
SYSTEM.EXCEPTION.

//避免

TRY
{
<SOME LOGIC>
}
CATCH(EXCEPTION EXC)
{
<ERROR HANDLING>
}

//
推荐

TRY
{
<SOME LOGIC>
}
CATCH(SYSTEM.NULLREFERENCEEXCEPTION EXC)
{
<ERROR HANDLING>
}
CATCH(SYSTEM.ARGUMENTOUTOFRANGEEXCEPTION EXC)
{
<ERROR HANDLING>
}
CATCH(SYSTEM.INVALIDCASTEXCEPTION EXC)
{
<ERROR HANDLING>
}

12使用TRY...CATCH...FINALLY时, 要在FINALLY里释放占用的资源如连接,文件流等

不然在CATCH到错误后占用的资源不能释放

TRY
{}
CATCH
{}
FINALLY
{
CONNTION.CLOSE();
}

13
不要用EXCEPTION控制程序流程
有些程序员可能会使用异常来实现一些流程控制例如:

TRY{
RESULT=100/NUM;
}
CATCH(EXCEPTION E)
{
RESULT=0;
}

但实际上,EXCEPTION是非常消耗系统性能的除非必要,不应当使用异常控制来实现程序流程上面的代码应当写为:

IF(NUM!=0)
RESULT=100/NUM;
ELSE
RESULT=0;


14
避免使用递归调用和嵌套循环,使用他们会严重影响性能,在不得不用的时候才使用

15禁用VB和JSCRIPT动态数据类型

应当始终显示地申明变量数据类型,这能够节约程序的执行时间以往,开发人员喜欢使用 VISUAL BASICVBSCRIPT 和 JSCRIPT 的原因之一就是它们所谓无类型的性质变量不需要显式类型声明,并能够简单地通过使用来创建它们当从一个类型到另一个类型进行分配时,转换将自动执行不过,这种便利会大大损害应用程序的性能

如:

为了获得最佳的性能,当声明 JSCRIPT .NET 变量时,请为其分配一个类型例如,
VAR A : STRING;


四使用缓存


1使用OUTPUT CACHE缓存数据

提供缓存功能是ASP中非常强大的一种功能曾看到过某些评测说:ASP程序的性能比SUN的JSP应用程序性能快上几倍,实际上,该评测程序非常重要的一点就是使用了很多ASP的缓存功能

如果你的组件是要在ASP应用程序中运行,你只要把SYSTEM.WEB.DLL引用到你的项目中就可以了然后用HTTPRUNTIME.CACHE属性就可访问CACHE了(也可以通过PAGE.CACHE或HTTPCONTEXT.CACHE访问)


有以下几条缓存数据的规则第一,数据可能会被频繁的被使用,这种数据可以缓存第二,数据的访问频率非常高,或者一个数据的访问频率不高,但是它的生存周期很长,这样的数据最好也缓存起来第三是一个常常被忽略的问题,有时候我们缓存了太多数据,通常在一台X86的机子上,如果你要缓存的数据超过800M的话,就会出现内存溢出的错误所以说缓存是有限的换名话说,你应该估计缓存集的大小,把缓存集的大小限制在10以内,否则它可能会出问题在ASP中,如果缓存过大的话也会报内存溢出错误,特别是如果缓存大的DATASET对象的时候


这里有几个你必须了解的重要的缓存机制首先是缓存实现了最近使用原则( A LEAST-RECENTLY-USED ALGORITHM),当缓存少的时候,它会自动的强制清除那些无用的缓存其次 条件依赖强制清除原则(EXPIRATION DEPENDENCIES),条件可以是时间,关键字和文件以时间作为条件是最常用的在ASP2.0中增加一更强的条件,就是数据库条件当数据库中的数据发生变化时,就会强制清除缓存


使用 ASP.NET 缓存机制有两点需要注意首先,不要缓存太多项缓存每个项均有开销,特别是在内存使用方面不要缓存容易重新计算和很少使用的项其次,给缓存的项分配的有效期不要太短很快到期的项会导致缓存中不必要的周转,并且经常导致更多的代码清除和垃圾回收工作若关心此问题,请监视与 ASP.NET APPLICATIONS 性能对象关联的 CACHE TOTAL TURNOVER RATE 性能计数器高周转率可能说明存在问题,特别是当项在到期前被移除时这也称作内存压力


切记:


应该:

应该缓存那些经常被访问同时变化频率不大的数据

应该缓存整个应用程序都要使用的设置或对象,但这些设置和对象必须在其生存期内不会变化

不应该:

不要缓存个人信息如果缓存个人信息,其他人很容易取得这些信息
不要缓存包含基于时间值的页面,否则浏览者将无法理解为何时间总是滞后
不要缓存用户随时都会修改的对象,如购物车



ASP中常用的缓存方式有:


1)页面缓存(对整个页面进行缓存
)

<%//RESPONSE.ADDHEADER("LAST-MODIFIED", DATETIME.NOW.ADDHOURS(-1).TOSTRING("R"));%>
<% RESPONSE.ADDHEADER("CACHE-CONTROL", "MAX-AGE=86400"); %>
<%//RESPONSE.ADDHEADER("DATE", DATETIME.NOW.ADDMINUTES(-59).TOSTRING("R"));%>

<%@PAGE OUTPUTCACHE VARYBYPARAMS=CLASSID;PAGE DURATION=3600 %>

2.0中为:

<%@OUTPUTCACHE VARYBYPARAM=CLASSID;PAGE DURATION=3600 %>

你就可以有效的利用第一次请求里生成的页面输出缓存内容,3600秒后重新生成一道页面内容这种技术其实也是运用一些低层的CACHE API来实现用页面输出缓存有几个参数可以配置,如上面所说的VARYBYPARAMS参数,该参数表示什么时候触发重输出的条件,也可以指定在 HTTP GET或HTTP POST 请求模式下缓存输出

例如当我们设置该参数为VARYBYPARAMS=CLASSID;PAGE的时候,DEFAULT.ASPX?CLASSID=3&PAGE=1 请求的输出都会被缓存起来没有参数,或不用参数时用NONE如果传递的参数不止一个,那么即使字符串参数与值都相同,但排列次序不同,那么在请求页面时,也将生成不同的缓存页例如DEFAULT.ASPX?FIRST=1&LAST=1 和DEFAULT.ASPX?LAST=1&FIRST=1虽然参数完全相同,但由于排列次序不同,将生成两个不同的缓存页


许多人都没有意识到当用页面输出缓存的时候,ASP也会生成HTTP头集(HTTP HEADER)保存在下游的缓存服务器中,这些信息可以用于MICROSOFT INTERNET安全性中以及加速服务器的响应速度当HTTP缓存的头被重置时,请求的内容会被缓在网络资源中,当客户端再次请求该内容时,就不会再从源服务器上获得内容了,而直接从缓存中获得内容

虽然用页面输出缓存不提高你的应用程序性能,但是它能减少了从的服务器中加载已缓存页面内容的次数当然,这仅限于缓存匿名用户可以访问的页面因为一旦页面被缓存后,就不能再执行授权操作了



2)片断缓存(对页面的某一部分,如某个USER CONTROL进行缓存
)

<%@ OUTPUTCACHE DURATION="60" VARYBYPARAM=TEXTBOX1;TEXTBOX2 %>

在ASP中,除了在页面范围内使用缓存,也还可以针对USER CONTROL使用OUTPUT CACHE参数实现对用户控件的缓存同样的,一个页面中相同类型的控件也可以有多个不同的缓存可以根据参数来实现不同的缓存页面缓存和片断缓存可以同时使用



3)数据缓存

数据缓存是一种强大而又非常简单的缓存机制,它可以在缓存区中为每个应用程序保存各种对象,这些对象可以根据HTTP的请求被调用,但是在各个不同的应用程序中这些对象都是私有的
数据缓存是通过CACHE类来实现的当应用程序建立时,一个CACHE类就同时被建立,缓存实例的生存周期就是应用程序的生存周期,它会随着应用程序的重新运行而重建,通过CACHE类的方法,我们可以将数据对象放入缓存区,然后通过关键字匹配寻找并使用这些对象
CACHE类通过一个借口来控制所有需要缓存的内容,包括规定缓存的时间和缓存方式,可以通过如下方法添加缓存对象:

CACHE[关键字] = 关键字的取值;

然后通过下面的方法来访问这个对象:

STRING MKEYVALUE = ;
IF(CACHE[
关键字
] != NULL)
{
MKEYVALUE = CACHE[关键字
];
}

注意PAGE.CACHE和HTTPCONTEXT.CURRENT.CACHE区别
:
它们指的同一个对象,在PAGE里,用PAGE.CACHE,如果在GLOBAL.ASAX或自己的类里用:HTTPCONTEXT.CURRENT.CACHE,在有些事件中,由于其没有HTTPCONTEXT,就用
HTTPRUNTIME.CACHE


数据缓存的过期依赖条件


某种意义上,CACHE和APPLICATION是一样的,都是一种公有的对象为了取得缓存与数据有效性之间的平衡,可以根据需要对缓存过期策略进行合理的设置


文件依赖
CACHE.INSERT (MYDATA, SOURCE , NEW CACHEDEPENDENCY(SERVER.MAPPATH(AUTHORS.XML)));
此代码的含义是当AUTHORS.XML文件不发生变化的时候,缓存MYDATA始终有效


时间依赖
设定1小时后过期,这是一种绝对过期
CACHE.INSERT(MYDATA,SOURCE,NULL ,DATETIME.NOW.ADDHOURS(1),TIMESPAN.ZERO);


相对过期依赖
当DATASET不再发生变化20分钟以后,缓存过期
CACHE.INSERT(MYDATA,SOURCE,NULL,DATETIME.MAXVALUE,TIMESPAN.FROMMINUTES(20));

一个示例:

//绝对过期!!!(用来保存公用的,数据量小的数据对象,可以是任何对象
)
//设置

IF (SYSTEM.WEB.HTTPCONTEXT.CURRENT.CACHE["OK"] == NULL)
SYSTEM.WEB.HTTPCONTEXT.CURRENT.CACHE.INSERT("OK", "DATA", NULL, DATETIME.NOW.ADDSECONDS(300),SYSTEM.WEB.CACHING.CACHE.NOSLIDINGEXPIRATION);
//
读取
IF(SYSTEM.WEB.HTTPCONTEXT.CURRENT.CACHE["OK"]!=NULL)
THIS.RESPONSE.WRITE(CONVERT.TOSTRING(SYSTEM.WEB.HTTPCONTEXT.CURRENT.CACHE.GET("OK")));

最后要注意:
在WEB FORM调试期间不能使用缓存,否则你对页面所做的修改在缓存过期之前不会得到显式加载正确的做法应该是在调试结束之后,给需要放入缓存的页面用户控件或对象加上缓存指令最后建立部署和安装项目,生成安装数据包,这时候就可以到服务器上去发布你的产品了

详细参考:
HTTP://HI.BAIDU.COM/ERICS_LELE/BLOG/ITEM/674E46E7622F262CB83820C6.HTML
HTTP://BLOG.CSDN/CHENGKING/ARCHIVE/2005/10/03/494545.ASPX


2预请求缓存

虽然CACHE API设计成用来保存某段时间的数据,而预请求缓存只是保存某个时期的某个请求的内容如果某个请求的访问频率高,而且这个请求只需要提取,应用,修改或者更新数据一次那么就可以预缓存该请求我们举个例子来说明


在CS的论坛应用程序中,每一个页面的服务器控件都要求得到用于决定它的皮肤(SKIN)的自定义的数据,以决定用哪个样式表及其它的一些个性化的东西这里面的某些数据可能要长时间的保存,有些时间则不然,如控件的SKIN数据,它只需要应用一次,而后就可以一直使用


要实现预请求缓存,用ASP 的HTTPCONTEXT类,HTTPCONTEXT类的实例在每一个请求中创建,在请求期间的任何地方都可以通过HTTPCONTEXT.CURRENT属性访问HTTPCONTEXT类有一个ITEMS集合属性,在请求期间所有的对象和数据都被添加到这个集合中缓存起来和你用CACHE缓存访问频率高数据一样,你可以用HTTPCONTEXT.ITEMS缓存那些每个请求都要用到的基础数据它背后的逻辑很简单:我们向HTTPCONTEXT.ITEMS中添加一个数据,然后再从它里面读出数据

posted @ 2009-04-03 09:42    阅读(228)  评论(0编辑  收藏  举报