精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>● ASP>>ASP技巧>>22个提高ASP性能的技巧(2)

主题:22个提高ASP性能的技巧(2)
发信人: i_am_trueman(粗蚊)
整理人: i_am_trueman(2004-02-28 19:30:40), 站内信件
技巧9:进程外执行以性能换取可靠性  
ASP和MTS/COM+都有选项让你来用可靠性换取性能。当建立和发布你的应用时,你应该理解这项交易的内幕。  

ASP选项  
ASP应用有三种运行方法可选择。在IIS 5.0中,引入“分离级别(isolation   
level)”这个术语来描述这些选项。三种分离级别分别是:低(Low),中  
(Medium)和高(High)。  

低分离级 这种级别被所有版本的IIS支持,并且速度也是最快的。它在  
Inetinfo.exe--主要的IIS进程--中运行ASP。如果ASP应用崩溃,IIS也将崩溃。  
(在IIS 4.0中,网管必须用诸如InetMon之类的工具来监视IIS,一旦IIS停止,运行批处理文件。IIS 5.0引入了“可靠的重启(reliable restart)”,会自动重新启动失败的服务器。   
中分离级 从IIS 5.0开始引入的新级别,指进程外运行,即ASP运行在IIS进程之外。  
在中分离级中,所有的ASP应用共享一个进程空间。把多个进程外应用在同个空间中运行,减少了进程的树木。中分离级是IIS 5.0的默认级别。   
高分离级 IIS 4.0和IIS 5.0都支持。高分离级也是进程外的。如果ASP崩溃了,Web服务器并不崩溃。ASP应用会在下个ASP请求到达的时候自动重启。每个被配置为高分离级的ASP应用有自己的进程空间;这将每个ASP应用保护起来。它的缺点是对每个ASP应用需要一个分离的进程;这增加了许多资源消耗。   
哪种选项是最好的。在IIS 4.0中,进程外运行将使性能急剧下降;在IIS 5.0中,许多改进使进程外ASP应用的代价降到最低。事实上,在许多测试中,IIS 5.0中的ASP进程外应用比II4 4.0中的进程内运行都快。但无论如何,在任何平台上,还是进程内(低分离级)运行能带来最佳的性能。然而,在相对低点击率或低最大吞吐量的情况下,低分离级不会带来任何益处;因此,除非每个Web服务器需要应付成千上百的页面请求,不然你不会需要用低分离级。通常,需要在多个配置下进行测试,才能决定使用哪种配置。   
注意:当在进程外运行ASP应用时(中或低分离级),ASP应用运行在NT 4上的MTS中或Windows 2000的COM+中;就是说,在NT4中,ASP应用运行在Mtx.exe中;在  
Windows 2000中,ASP应用运行在DllHost.exe中。你可以在任务管理器中看到这些进程在运行。  

COM选项  
COM组件也有三种配置选项,但不完全对应于ASP的选项。COM组件可以是“无配置的(Unconfigured)”、作为一个库应用(Library Application)或是作为一个服务应用(Server Application)。“无配置的”意味着组件不注册到COM+中,组件将在调用者进程空间中运行;即“进程内”。库应用也是进程内的,但可以从COM+的服务,如安全、事务和上下文支持,中获益。服务应用则被配置成运行在自己的进程空间内。  

“无配置”比库应用有一点优越性;而库应用比服务应用在性能上更优越。这是因为库应用和ASP是在同一个进程内的,而服务应用是运行在自己的进程空间里的。进程间调用比进程内调用的代价高。同样,在进程间传递如记录集这样的数据,需要在两个进程间复制所有的数据。  

缺陷!当使用COM服务应用时,要想在ASP和COM间传送数据,必须保证对象实现了“按值排列(marshall-by-valu)”,或者说MBV。实现了MBV的对象将自身从一个进程复制到另一个进程。这比下面的方法好:对象留在创建者进程,其他进程重复调用创建进程来使用对象。无连接ADO记录集是MBV,有连接记录集就不是。  
Scripting.Dictonary对象没有实现MBV,不能在进程之间传递。最后,对VB程序员的一个提示:MBV不是通过用ByVal来传递参数。MBV是原始组件作者实现的。  

怎样做?  
推荐的用可靠性换取性能的配置:  

在IIS 4.0上,用ASP的低分离级,并使用MTS服务包。   
在IIS 5.0SHANG,用ASP的中分离级,使用COM+的库应用。   
技巧10:使用Option Explicit  
在.asp文件中使用Option Explicit。该指示放在.asp文件的顶部,强制开发者在使用任何变量之前必须定义它。许多程序员认为这有助于调试程序,因为它消除了打字错误的可能(如将MyXMLString=敲成MyXLMString=)  

另外一点可能更加重要:已定义变量比未定义的变量快。ASP每次是用名字来引用未定义变量的;而另一方面,每个已定义变量有一个序号,ASP用这个序号来引用已定义变量。既然Option Explicit强制变量定义,就保证了所有的变量都是已定义的,访问速度就更快了。  

技巧11:在子过程和函数中使用本地变量  
本地变量是那些在子过程和函数中定义的变量。在函数和子过程中,访问本地变量比访问全局变量更快。使用本地变量也使代码更干净,因此尽量使用本地变量吧。  

技巧12:将常用数据复制到脚本变量中  
当访问ASP中的COM对象时,应该将常用对象数据复制到脚本变量中。着将减少COM方法调用。而COM方法调用代价相对比访问脚本数据更高。当访问Collection和  
Dictonary对象时,这项技术也能消减高昂的查询代价。  

通常,当准备不止一次访问一个对象数据时,应该将这个数据放当一个脚本对象中。  
这项优化的主要目标是Request变量(Form和QueryString变量)。例如,你的站点传递一个叫UserID的QueryString变量,假定在一个特定页UserID被引用十次。在ASP页面的顶部,将UserID的值赋给一个变量,来替代十次的调用Request  
("UserID"),将接生9次COM调用。  

在实际中,访问COM属性或方法的昂贵代价可能比较隐蔽。下面是一个例子,显示一段普通的代码:  

Foo.bar.blah.baz = Foo.bar.blah.qaz(1)  
If Foo.bar.blah.zaq = Foo.bar.blah.abc Then ' ...  

下面是这段代码运行的步骤:  

1. 变量Foo被解析为一个全局对象  
2. 变量bar被解析为Foo的一个成员。这触发一次COM方法调用  
3. 变量blash被解析为Foo.bar的一个成员。同样,这也触发一次COM方法调用  
4. 变量qaz被解析为Foo.bar.blash的一个成员。对,这也触发一次COM方法调用  
5. 调用 Foo.bar.blah.qaz(1)。一个或多个COM方法调用。获取图片?  
6. 重复步骤1到步骤3来解析baz。系统不知道调用qaz是否会改变对象模型,所以步骤1到步骤3又执行了一次,来解析baz  
7. 解析出baz是Foo.bar.blah的一个成员,执行属性put.  
8. 重复步骤1到步骤3来解析zaq  
9. 重复步骤1到步骤3来解析abc  

正如你所看到的,这是多么低效(并且慢)。快速的方法是按如下代码写VBScript:  

Set myobj = Foo.bar.blah ' do the resolution of blah ONCE  
Myobj.baz = myobj.qaz(1)  
If Myobj.zaq = Myobj.abc Then '...  

如果你用的是VBScript 5.0或更后的版本,可以使用With语句:  

With Foo.bar.blah  
.baz = .qaz(1)  
If .zaq = .abc Then '...  
...  
End With  


技巧13:避免使用可变数组  
尽量避免使用可变数组。既然关心性能,最好还是在数组初始化的时候就设置好它可能的最大大小。当然,这不是说你明知不需要几M的内存,但还是应该给数组分配了那么多。  

下面的代码是一个无理使用Redim的示范:  

<%
Dim MyArray()
Redim MyArray(2)
MyArray(0) = "hello"
MyArray(1) = "good-bye"
MyArray(2) = "farewell"
...
Redim Preserve MyArray(5)
MyArray(3) = "more stuff"
MyArray(4) = "even more stuff"
MyArray(5) = "yet more stuff"
%>  

简单地将数组初始化的时候定义成正确的大小(这里应该是5)远比Redim数组使它变大好。你可能会浪费一些内存(如果你最后没有用完所有的元素),但得到的是速度!  

技巧14:使用响应缓冲(Response Buffering)  
打开“响应缓冲”就可以缓冲整个页面的输出,这样可以减少向浏览器写的次数,提高了总体性能。每次写浏览器都要耗费一定的时间和资源,因此减少写浏览器次数能提高性能;同时,TCP/IP协议发送少的大块数据比发送多的小块数据效率更高。  

有两种方法可以打开响应缓冲。首先,可以使用Internet Service Manager来打开整个应用的响应缓冲。这是推荐的方法。在IIS 4.0和IIS 5.0中,新建一个应用时,响应缓冲缺省是打开的。第二种方法:针对每个独立的ASP页面,可以通过在页面顶部放置如下代码来打开响应缓冲:  

<% Response.Buffer = True %>  

这行语句必须在所有缓冲数据写之前执行(就是说,在所有HTML和通过  
Response.Cookies设置Cookie之前)。通常,最好是为整个应用打开响应缓冲;这样你就不用在每个ASP页面顶部写上面那条语句了。  

Response.Flush  

对于响应缓冲,因为用户在看到东西之前必须等待整个页面生成,所以用户可能够感觉到ASP页面响应比较慢(虽然整体响应时间缩短了);对一个运行时间较长的页面,可以同过Response.Buffer = False 来关掉响应缓冲;但更好的策略是使用  
Reponse.Flush方法。这个方法把所有已经由ASP生成的HTML输出到浏览器中。例  
如,一个1,000行的大表,在写完100行之后,ASP可以调用Response.Flush来强制把结果写到浏览器中,这样,用户就可以在其余行生成之前先看到100行数据。这个技术能让你两全其美—响应缓冲和渐进式地在浏览器表现数据。  

(注意,在上面的1,000行表的例子中,很多浏览器在遇到</table>标记之前可能并不画出整个表。如果想让浏览器逐步显示出数据,可以将一个大表分成多个小表,然后对每个小表调用Response.Flush。新版本的IE会在下载完整个表之前显示表,并且如果指定了表的列宽,显示的速度会更快。)  

另外,当产生一个非常大的页面时,响应缓冲可能会消耗掉许多的服务器内存。这个问题也可以通过使用Response.Flush来解决。  

技巧15:脚本大块化和Response.Write语句  
VBScript语法<% = 表达式 %>把“表达式”的值写到ASP输出流中;但如果响应缓冲没有打开,每个这样的语句都会想浏览器写数据,就把网络流分成很多小的包。这样会慢。同样,零星的小段脚本和HTML导致频繁的在脚本引擎和HTML之间切换,降低了性能。因此,应该使用以下技巧:把小块内嵌表达式改成调用Response.Write。例如,在下面的例子中,每行的每个字段都向响应流中写数据,并且每行都在VBScript和HTML中切换:  

<table>  
<% For Each fld in rs.Fields %>  
<th><% = fld.Name %></th>  
<%
Next
While Not rs.EOF
%>  
<tr>  
<% For Each fld in rs.Fields %>  
<td><% = fld.Value %></td>  
<% Next
</tr>  
<% rs.MoveNext
Wend %>  
</table>  

下面是更有效的代码,每行只向响应流中写一次。所有的代码包含在一个VBScript块中:  

<table>  
<%
For each fld in rs.Fields
Response.Write ("<th>" & fld.Name & "</th>" & vbCrLf)  
Next  
While Not rs.EOF  
Response.Write ("<tr>")  
For Each fld in rs.Fields %>  
Response.Write("<td>" & fld.Value & "</td>" & vbCrLf)  
Next  
Response.Write "</tr>"  
Wend  
%>  
</table>  

当响应缓冲被禁止时,这个技巧非成的有效。最好打开响应缓冲,然后再看看批量地Response.Write对性能的提高。  

(在特定情况下,生成表的嵌套循环(While Not rs.EOF...)可以用GetString函数来替换)  

[关闭][返回]