如何增强ASP程序性能

如何增强ASP程序性能

 

---摘自《天极网》

简介

  性能是一个很重要的特征。你需要事先设计好性能指标,否则日后就要为此重新编写程序。就是说:要设想好怎样最佳化地执行ASP程序?

  本文提出了一些优化ASP应用和VBScript的技巧,许多技巧和缺陷都经过了研讨。这里列出的建议已经在http://www.microsoft.com 和其他站点上进行了测试,都工作得非常好。本文假设你具备ASP开发的基本知识,包括VBScript或者JScriptASP应用程序,ASP Session,以及其他ASP内置对象(RequestResponseServer)。

  通常,ASP的执行性能远远不仅仅依赖ASP代码本身!在本文的尾部列出了与性能相关的资源,它们含概了ASP和非ASP的部分,包含ActiveX Data ObjectsADO),Component Object ModelCOM),数据库(Database),以及Internet信息服务器(IIS)的配置。除了这些,还有一些非常好的链接值得你一看。

技巧1:在Web服务器上缓存经常使用的数据

  典型的情况是:ASP页面从后台存储中取回数据,然后以超文本标记语言(HTML)的形式形成结果。不管数据库的速度如何,从内存中取回数据要比从后台存储设备中快得多。从本地硬盘读取数据通常也非常快。所以,提高性能可以通过缓存服务器上的数据来实现,无论是将数据缓存在内存中,或者本地硬盘中。

  缓存是经典的“空间换时间”的折中方式。如果缓存得恰当,就可以看到显著的性能提升。为了让缓存有效,必须保证缓存数据是经常要重用的,而且也是计算起来繁琐的。装满陈旧数据的缓存是对内存的浪费。

  不经常改变的数据是缓存的较好对象,因为不需要随时考虑这些数据更新后的同步操作。组合框、参考表格、DHTML代码、扩展标记语言串、菜单以及站点配置变量(包括数据源名字DSNSInternet协议地址IP以及Web路径)都是很好的缓存对象。注意:要缓存数据表达式而不是数据本身。如果一个ASP页面经常变化并且很费力去缓存(比如整个产品目录),就要考虑预产生HTML,而不是每次发生请求时再描述它。

技巧2:在ApplicationSession对象中缓存经常使用的数据

  ASP中的ApplicationSession对象是在内存中缓存数据的便利容器。你可以将数据赋值给ApplicationSession对象,这些数据在HTTP调用期间将一直保持在内存中。Session中的数据是为每一个用户服务的,Application中的数据是所有用户共享的。

  何时需要在ApplicationSession中装入数据?通常,当应用程序启动或者会话开始时,数据就被装入了。为了在这时装入数据,在Application OnStart()或者Session OnStart()中分别添加适当的代码。这些函数位于文件Global.asa中,如果原来不存在,就添加上。也可以在数据首次需要的时候调入,在ASP页面中添加代码,检查数据是否存在,如果没有发现,就调入它。这里有一个例子,它代表了被称为“lazy evalution”的经典性能处理技术:直到需要时,再去计算。例子如下:

<%
     
     
Function GetEmploymentStatusList
     
     
 Dim d
     
     
 d = Application("EmploymentStatusList")
     
     
 If d = "" Then
     
     
 ' FetchEmploymentStatusList function (not shown)
     
     
 ' fetches data from DB, returns an Array
     
     
 d = FetchEmploymentStatusList()
     
     
 Application("EmploymentStatusList") = d
     
     
 End If
     
     
 GetEmploymentStatusList = d
     
     
End Function
     
     
%>
     
     

对于不同的数据,可以编写类似的函数代码。

  数据应该按什么格式保存?任何变量类型都可以,因为所有的脚本变量都是不同的。比如说,可以保存为字符串、整型或者数据。通常,将ADO记录集的内容存储到这些变量类型中一个。为了从ADO记录集中取出数据,需要手工地拷贝数据到VBScript变量中,每次一个字段。使用任意一个ADO记录集的函数functions GetRows(),GetString() 或者 Save() (ADO 2.5)都非常得快速而且简单,这里有个函数,描述了如何使用GetRows()返回记录集数据的数组:

' Get Recordset, return as an Array
     
     
Function FetchEmploymentStatusList
     
     
 Dim rs 
     
     
 Set rs = CreateObject("ADODB.Recordset")
     
     
 rs.Open "select StatusName, StatusID from EmployeeStatus", _
     
     
 "dsn=employees;uid=sa;pwd=;"
     
     
 FetchEmploymentStatusList = rs.GetRows() " Return data as an Array
     
     
 rs.Close
     
     
 Set rs = Nothing
     
     
End Function
     
     

上述代码的一个更深的技巧是为列表缓存了HTML。下面是个简单的例子:

' Get Recordset, return as HTML Option list
     
     
Function FetchEmploymentStatusList
     
     
 Dim rs, fldName, s
     
     
 Set rs = CreateObject("ADODB.Recordset")
     
     
 rs.Open "select StatusName, StatusID from EmployeeStatus", _
     
     
 "dsn=employees;uid=sa;pwd=;"
     
     
 s = "<select name=""EmploymentStatus">" & vbCrLf
     
     
 Set fldName = rs.Fields("StatusName") ' ADO Field Binding
     
     
 Do Until rs.EOF
     
     
 ' Next line violates Don't Do String Concats,
     
     
 ' but it's OK because we are building a cache
     
     
 s = s & " <option>" & fldName & "</option>" & vbCrLf
     
     
 rs.MoveNext
     
     
 Loop
     
     
 s = s & "</select>" & vbCrLf
     
     
 rs.Close
     
     
 Set rs = Nothing ' See Release Early
   
   
 FetchEmploymentStatusList = s ' Return data as a String
     
     
End Function
     
     

在合适的环境下,可以在Application或者Session中缓存ADO记录集本身,但是有2点提示:

  • ADO必须是自由线程标记的
  • 需要使用disconnected recordset方式

  如果不能保证上述2个条件,就不要缓存ADO记录集,因为这会产生很大的危险性。

  当在ApplicationSession中保存数据后,数据将一直保持,除非程序改变它、Session变量到期或者Web应用程序重新启动。如果数据需要更新,怎么办?可以调用只有管理员才能访问的ASP页面来更新数据,或者,通过函数周期性的自动更新数据。下面的例子中,与缓存数据一起保存了时钟标记,过一段时间后,就刷新数据。

<%
     
     
' error handing not shown...
     
     
Const UPDATE_INTERVAL = 300 ' Refresh interval, in seconds
     
     

   
   
    
     
   
   
' Function to return the employment status list
     
     
Function GetEmploymentStatusList
     
     
 UpdateEmploymentStatus
     
     
 GetEmploymentStatusList = Application("EmploymentStatusList")
     
     
End Function
     
     

   
   
    
     
   
   
' Periodically update the cached data
     
     
Sub UpdateEmploymentStatusList
     
     
 Dim d, strLastUpdate
     
     
 strLastUpdate = Application("LastUpdate")
     
     
 If (strLastUpdate = "") Or _
     
     
 (UPDATE_INTERVAL < DateDiff("s", strLastUpdate, Now)) Then
     
     

   
   
    
     
   
   
 ' Note: two or more calls might get in here. This is okay and will simply
     
     
 ' result in a few unnecessary fetches (there is a workaround for this)
     
     

   
   
    
     
   
   
 ' FetchEmploymentStatusList function (not shown)
     
     
 ' fetches data from DB, returns an Array
     
     
 d = FetchEmploymentStatusList()
     
     

   
   
    
     
   
   
 ' Update the Application object. Use Application.Lock()
     
     
 ' to ensure consistent data
     
     
 Application.Lock
     
     
 Application("EmploymentStatusList") = d
     
     
 Application("LastUpdate") = CStr(Now)
     
     
 Application.Unlock
     
     
 End If
     
     
End Sub
     
     

有另外一个例子,请参阅 World’s Fastest ListBox with Application Data

  必须意识到,在Session或者Application对象中缓存大容量的数组不是一个好的方法。存取数组中任何元素前,脚本语言的规则要求首先要建立整个数组的临时备份。比如,如果在Application对象中缓存一个100000个元素的数组,其中包含U.S.邮政编码与本地气象站的对应关系,ASP就必须首先拷贝所有100000个气象站信息到临时数组中,然后才能选择其中一个字符串进行处理。在这种情况下,创建一个定制的组件,编写一个方法存储气象站信息,是非常好的方法。

技巧3:在Web服务器磁盘上缓存数据和HTML页面

  有时候,有“许多”数据要在内存中缓存。“许多”是相对而言的,它取决于能消耗多少内存、缓存项目的数量以及取回数据的频度。任何情况下,如果需要在内存中缓存大量的数据,请考虑以text或者XML文件格式在Web服务器硬盘上做缓存。当然,也可以混合使用硬盘缓存数据以及内存缓存数据,从而达到最佳缓存。

  注意:当测试一个单一ASP页面的性能时,从磁盘取回数据不一定比从网络数据库中取回数据快,但是缓存减少了网络数据库的调用。在大规模调用时,这将明显地提高网络的吞吐能力。缓存一个费时的查询结果是非常有用的,比如对于一个复杂的存储过程,或者大量的结果数据。

  ASPCOM提供了几种建立基于磁盘缓冲配置的工具。ADO记录集的Save()和 Open()函数负责保存和调入磁盘上的记录集。另外还有一些组件:

  • Scripting.FileSystemObject 允许你创建、读取和写文件
  • MSXMLMicrosoft XML 解析器随Internet Explorer而来,支持保存和装入XML文档
  • LookupTable对象(比如在MSN上使用)是从磁盘调入简单列表的很好选择。

  最后,考虑缓存磁盘数据的表达式,而不是数据本身。预处理的HTML可以存储为.htm或者.asp文件,链接直接指向它们。使用诸如XBuilder或者Microsoft SQL Server Internet发布类的商业工具,能够自动处理这些过程。而且,也可以在.asp文件中包含HTML程序片断。同样,也可使用FileSystemObject从磁盘上读取HTML文件,或者使用XML for early rendering来做这个工作。

技巧4:避免在ApplicationSession对象中缓存非轻快型组件

  在ApplicationSession对象中缓存数据是一个很好的方法,但是,缓存COM对象却有严重的缺陷。在ApplicationSession对象中缓存经常使用的COM对象这个工作是非常吸引人的,但是很不幸,许多COM对象,包括用Visual Basic 6.0或者以前版本编写的对象组件,当存储在ApplicationSession对象中后,都会产生严重的瓶颈问题。

  特别地,当组件编写得不是很轻巧时,就极可能产生瓶颈问题。一个轻型组件就是标记了ThreadingModel=Both的组件,其中合计了自由线程的排列(FTM),或者标记了ThreadingModel=NeutralNeutral模式是Windows2000COM+中的新特征)。下面的组件不是轻型的:

  • Free-threaded组件(除非被集合成FTM
  • Apartment-threaded组件
  • Single-threaded组件

  Configured components不是轻型组件,除非它们是Neutral-threaded的。Apartment-threaded组件和其他非轻型组件在页范围内工作得很好,就是说,它们是在一个单一ASP页面中创建并释放的。

  如果缓存了非轻型组件,将会发生什么错误?在Session对象中缓存的非轻型组件将会锁住会话。ASP维护着一个响应请求的工作线程池,通常,新的请求被第一个可用的工作线程控制。如果一个会话被锁在一个线程中,那么请求就被迫等待到相关的线程变为可用。这里有一个类比:你前往一个超级市场,挑选了一些食品,并在3号付款台付款。从那以后,只要在那个超级市场买食品付款,你就会经常到3号付款台去,虽然其他的付款台人少些甚至没有人。

技巧5:不要在ApplicationSession对象中缓存数据库连接

  缓存ADO连接通常不是一个好的策略。如果一个连接对象被存储在Application对象中,并在所有的页面使用,那么所有页面将会争夺该连接的使用。如果存储在ASP Session对象中,那么将要为每一个用户都打开数据库连接。这将挫败连接池的使用意图,并且在Web服务器和数据库上都施加了不必要的高代价压力。

  为了替代缓存数据库连接,可以在使用ADO的每个ASP页面中创建并释放ADO对象。这将非常有效,因为IIS拥有内建的数据库连接池。更准确地说,IIS自动处理OLEDBODBC连接池,这将保证在每个页面创建并且释放连接的工作高效进行。

  由于连接的记录集存储了数据库连接的参考,所以,不要在ApplicationSession对象中缓存连接的记录集。然而,可以安全地缓存disconnected类型的记录集,它们并不保存相应数据库连接的参考。为了断开记录集,执行下面2步:

 Set rs = Server.CreateObject("ADODB.RecordSet")
     
     
 rs.CursorLocation = adUseClient ' step 1
     
     

   
   
    
     
   
   
 ' Populate the recordset with data
     
     
 rs.Open strQuery, strProv
     
     

   
   
    
     
   
   
 ' Now disconnect the recordset from the data provider and data source
     
     
 rs.ActiveConnection = Nothing ' step 2
     
     

  更多的关于连接池的信息请访问 ADO and SQL Server

 

技巧6:聪明地使用Session对象

  Session在繁忙站点上使用时有几个缺陷。繁忙的意思是:站点上每秒有上百的页面被请求,或者同时有上千的访问用户。这个技巧对于那些要求水平扩展强的站点非常重要,也就是指这些站点:它们利用多个服务器完成数据装载或者处理大量容错。对于小型站点,比如内部网IntranetSession是非常值得提倡的。

  再次重申,ASP自动地为每一个首次点击Web服务器的用户创建一个Session,每一个Session占有大约10KB的内存,生存期默认是20分钟。

  使用Session最大的问题不是性能,而是扩展性,Session不能跨越多个Web服务器,一旦在一个服务器上创建了Session,它的数据就驻留在那里。这意味着,如果在Web上使用Session,你就得为每一个直接访问存放Session服务器的用户请求设计一个策略。这就是将用户Web服务器上,术语“sticky sessions”就来源于此。如果Web服务器遇到障碍,“Stuck”用户就会丢失他们的Session状态,因为Session不保留在磁盘上。

  执行粘性session的策略包括硬件与软件解决方式,比如windows2000高级服务器中的 Network Load Balancing 以及Cisco公司的Local Director,但换取这些要牺牲一定的扩展性。

  Application对象也不能跨越服务器。如果需要在Web群中共享并更新Application数据,就需要使用后台数据库。然而,只读Application数据在Web群中仍然很有用。

  许多对任务要求严格的站点都要设立至少2Web服务器,所以在设计严格任务的应用程序时,就需要执行“sticky sessions”,或者简单地避免使用Session,同时也可以采取其他保存用户状态到独立Web服务器的管理技术。

  如果不使用Session,一定要确认将它们关闭,这可以通过Internet服务管理器实现。如果决定使用Session,可以通过几种方法来最小化它们的影响。

  可以将不需要Session的内容(比如帮助画面,访问者区域,等等)移动到关闭Session的独立ASP应用程序中。在基础页面上,可以给ASP一个指示,让它不需要使用Session。将下面的代码直接加入到ASP页面的头部:
  

<% @EnableSessionState=False %>
     
     

  使用这个指示的一个很好的解释是在框架结构中Session创建了一个有趣的问题。ASP确保在一个时刻只有一个来自Session的请求被执行,这就确保了如果浏览器为单个用户请求多个页面时,只有一个ASP请求在那时能够接受Session,如此就避免了存取Session对象时的多线程问题。很不幸,在框架结构中的所有页面将按照连续的顺序显示出来,一个接一个,而不是同时,所以用户为了看到整个框架必须要等很长时间。规则是:如果一定的框架页面没有使用Session,就一定要告诉ASP直接使用@EnableSessionState=False

  除了使用Session对象,还有许多其他管理会话状态的选择。对于小数量的状态(小于4KB),我们通常建议使用cookie、查询字符串变量以及表单隐藏域。对于象购物车一样的大数量数据,后台数据库是最合适的选择。

技巧7:将代码装入COM对象中

  如果要编写很多VBScript或者JScript,为了提个性能,可以将代码编写成COM对象并且编译使用。编译代码基本上比解释性代码运行快许多,编译组件对象可通过“early binding”存取其他COM对象,这比在脚本中调用组件要有效。

这么做有许多优点:

  • COM对象有益于从商业规则中独立出表达式规则
  • COM对象使代码重用变为可能
  • 许多开发者发现用VBC++或者Visual J++编写程序,比ASP更容易调试

  COM对象也有缺点,包括初始开发时间和对不同编程技巧的需要。注意将少量ASP代码做成COM对象组件不会有好处,反而可能导致性能的损失,从而失去了编译代码的优势。怎样组合使用ASP脚本和COM对象达到最佳性能是一个测试的问题。我们注意到微软公司已经大规模在Windows 2000/IIS 5.0上提高了脚本与ADO的性能,由此,随着IIS5.0版本的引进,减少了编译代码的性能优势。

技巧8:使用Option Explicit

  要在ASP文件中使用Option Explicit定义,并且放置到ASP文件的头部,从而强迫开发者在使用前声明所有的变量。许多程序员都认为这在应用程序调试时非常有用,因为它避免了产生错误类型变量以及偶然创建新变量的可能。

也许更重要的是,声明的变量要大大快于非声明变量。

技巧9:拷贝经常使用的数据到脚本变量中

  在ASP中存取COM对象时,应该拷贝经常使用的对象数据到脚本变量中,这样就减少了对COM对象的方法调用。这些调用要比存取脚本变量相对来说费时费力。当存取CollectionDictionary对象时,使用这项技巧也减少了昂贵的查找操作。

  通常,如果要不止一次地存取对象数据,就应将数据放入脚本变量中,对象数据主要也就是Request变量(表单和查询字符串变量)。比如,站点要传递一个叫做UserID的查询字符串变量,假设它将在一个特殊页面被引用12次,那么不需要调用Request“UserID”12次,只要在ASP页面的头部分配给UserID一个变量,然后在页面中使用它,这样做就节省了11COM方法的调用。

  实际中,存取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的一员
3
、变量blah被当作Foo.bar的一员
4
、变量qaz被当作Foo.bar.blah的一员
5
、调用Foo.bar.blah.quaz(1)
6
、再执行步骤13分解baz
7
、分解baz做为Foo.bar.blah的一员
8
、再执行步骤13分解zaq
9
、再执行步骤13一次分解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
     
     


注意:这个技巧也可以应用在VB编程中。

技巧10:避免再定义数组

  争取不要再定义数组。考虑到性能问题,如果机器的物理内存大小不够,最好按最差情况或者最佳情况设置数组的初始尺寸,需要时再重新定义。

下面的代码展示了DimRedim的使用:

< %
Dim MyArray()
Redim MyArray(2)
MyArray(0) = "hello"
MyArray(1) = "good-bye"
MyArray(2) = "farewell"
...
' some other code where you end up needing more space happens, then ...
Redim Preserve MyArray(5)
MyArray(3) = "more stuff"
MyArray(4) = "even more stuff"
MyArray(5) = "yet more stuff"
% >

  简单地定义数组初始尺寸为合适的大小是非常好的,而不要用Redim加大数组。这么做也许浪费了一些内存(如果没有完全地使用空间),但是赢得了速度。

 

技巧11:使用Response Buffering

  通过打开“response buffering”可以缓冲一个值得输出的整个页面内容,这将最小化输出到浏览器的数据量,从而提高了整体性能。每一次输出都耗费许多,所以写得越少,效果越好。TCP/IP在发送少量大的数据包时,要比发送大量小的数据包工作效率高,因为它是慢速启动并不断发送的。

  有2种方法打开Response Buffering。首先,可以使用Internet Services Manager为整个应用程序打开response buffering,这是推荐的方式,而且在IIS4.0IIS5.0中,默认状态下,response buffering是打开的。其次,在每一页面上,可以在头部放置如下代码开打开response buffering

< % Response.Buffer = True % >

  这段代码必须在任何数据输出到浏览器前被执行(就是说,在任何html内容显示前和在任何cookie被设置前)。通常情况下,为整个应用程序打开response buffering是很好的方案,这么做后就不用在每个页面头部设置如上的代码。

  关于打开response buffering的一个通用问题是:用户必须要等待整个页面全部产生后,才能看到内容。对于一个长时间运行的页面来说,可以设置Response.Buffer=False关闭缓冲。然后,好的策略是利用Response.Flush方法,它将输出所有已被ASP描述的HTML内容到浏览器。比如,在描述了一个1000行表格的100行后,ASP就可以使用Response.Flush来强迫输出这100行的内容到浏览器,这时用户就可以看到前100行数据,同时其余的行数据正在准备生成。

  注意,关于上面的1000行表格输出的例子,对于一些浏览器器来说,除非遇到< /table >标记,它们不会输出表格的任何内容。如果这样,可以将表格分割成许多含有少量行的多个表格,然后在每一个表格产生后,调用Response.Flush输出。新版的Internet Explorer在整个表格下载后才显示内容,并且,如果定义了表格的列宽度,生成表格的速度将特别快。

关于打开response buffering的另外一个问题是:当生成非常大的页面时,将消耗非常大的服务器内存。

技巧12:批处理单行脚本和Response.Write命令

  VBScript语法< % = expression % >的意思是输出expression的数值。如果response buffering没有打开,每个这样的语句将按照许多小数据包的形式输出数据到浏览器,这将降低程序性能。因此,请使用下面的技巧:替换紧挨着的多个一行表达式调用为一个调用,用Response.Write名称输出。比如,在下面的例子中,对于每行每个字段的输出,只有一个写操作:

<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>
     
     

下面是更有效率的代码,每行一个输出:

<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 buffering关闭时,这个技巧非常得有用。最好是打开response buffering,这样就可以看到批量的Response.Wwrite是如何提高了程序性能。

技巧13:使用< OBJECT >标记引用对象

  如果需要引用除代码路径外的对象(尤其是服务器、Application范围的对象),请在Global.asa文件中使用
< object runat=server id=objname >
标记来定义它们,而不要使用Server.CreateObject方法。使用Server.CreateObject方法可以立即创建对象,这样如果随后不使用它,就浪费了资源。使用
< object id=objname >
标记可以定义对象objname,但是直到它的属性或者方法首次使用时,objname才实际创建。

技巧14:避免在循环中串联字符串

许多人在循环中建立一个字符串,就象下面的样子:

s = "<table>" & vbCrLf
     
     
For Each fld in rs.Fields
     
     
 s = s & " <th>" & fld.Name & "</th> "
     
     
Next
     
     

   
   
    
     
   
   
While Not rs.EOF
     
     
 s = s & vbCrLf & " <tr>"
     
     
 For Each fld in rs.Fields
     
     
 s = s & " <td>" & fld.Value & "</td> "
     
     
 Next
     
     
 s = s & " </tr>"
     
     
 rs.MoveNext
     
     
Wend
     
     

   
   
    
     
   
   
s = s & vbCrLf & "</table>" & vbCrLf
     
     
Response.Write s
     
     

  这存在几个问题。首先是重复的连接字符串消耗二次方的时间,而且,运行的时间与计算的字段数量也是平方的关系。下面的简单例子更清楚地说明这一点:

s = ""
     
     
For i = Asc("A") to Asc("Z")
     
     
 s = s & Chr(i)
     
     
Next
     
     

  在第1层循环时,S的值是“A”;第2层循环时,VBScript要重新分配字符串,拷贝了2个字符(“AB”)到S中;第3层循环时,需要再重新分配并且拷贝3个字符到S中。在第N层循环时,就需要重新分配并拷贝N个字符到S中。那就是1+2+3+...+N的总和,也就是N*N1/2个拷贝。

  在上面的记录集例子中,如果有100个记录和5个字段,内部循环就要执行100*5500次,并且,完成所有拷贝和再分配任务的时间将接近500*500250000。这还是一个适当尺寸记录集的拷贝工作。

  在这个例子中,可以通过替换字符串连接为Response.Write()或者行内脚本(< % =fld.Value % >)的方法提高程序性能。如果response buffering打开(也应该打开),这将很快,因为Response.Write仅仅附加数据在缓冲区的尾部,而且不需要再分配。

  如果用JScript连接字符串,强烈建议使用+=操作符,就是说,使用s+=字符串,而不是s s字符串

技巧15:打开浏览器和代理的缓冲

  默认情况下,ASP禁止了浏览器和代理的缓冲功能。如果有一个每次都不要更新的页面,就应该打开浏览器和代理的缓冲,这将允许浏览器和代理在一段时间内使用该页面的缓冲拷贝数据。缓冲能够大大地减轻服务器的数据转载量,并提高用户的浏览性能。

哪些类别的动态页面适合被缓存呢?下面是一些例子:

  • 天气页面,每5分钟更新一次
  • 新闻或版本列表页面,每天更新2

  注意:使用浏览器或者代理缓存后,对Web服务器的点击次数就会减少。如果想精确地了解所有页面,或者对于邮递广告,就不适于使用浏览器和代理缓存了。

  浏览器缓存由HTTP“Expires”头参数控制,它由Web服务器发送给浏览器。ASP提供了2个简单的方法发送这个头部参数。设置页面在未来一定时间内到期,可以使用Response.Expires属性。下面的例子将告诉浏览器内容在10分钟后过期:

< % Response.Expires = 10 % >

  设置Response.Expires为负数或者0,就禁止了缓存。对第2个属性Response.ExpiresAbsolute的设置,允许指定在一个特殊时间到来时内容过期。

< % Response.ExpiresAbsolute = #May 31,2001 13:30:15# % >

  除了使用Response对象来设置到期时间,还可以在HTML文件头部写< META >标记。尽管代理不会注意到这个标记,但是一些浏览器可以。

< META HTTP-EQUIV="Expires" VALUE="May 31,2001 13:30:15" >

  最后,对于HTTP代理,使用Response.CacheControl可以指示是否缓存内容。设置属性为“Public”,打开代理缓存内容的功能。

< % Response.CacheControl = "Public" % >

  默认情况下,这个属性是设置成“Private”的。注意:不要让代理缓冲那些显示给特定用户的页面,因为代理可能会将属于其他用户的页面送给当前用户。

 

技巧16:在任何可能时使用Server.Transfer,而不要用Response.Redirect

  Response.Redirect告诉浏览器请求另一个不同的页面,这常常用于引导用户到登录页面或者出错处理页面。由于重定向强迫了一个新页面请求,结果是浏览器必须要与Web服务器循环2次,并且Web服务器必须处理一个额外的请求。IIS5.0引进了一个新功能Server.Transfer,它执行在同一服务器上的页面传输,这将避免额外的浏览器-Web服务器的数据循环,形成良好的系统性能,对于用户也有较好的响应时间。

技巧17:避免使用服务器变量

  存取服务器变量导致Web站点建立一个特殊的请求并收集所有的服务器变量,而并不是你要求的那个变量。这类似于在文件夹中取回一个特殊的文件,要想取回一个文件,就得首先获取所在文件夹的信息。

  不要存取非法的Request对象(比如Request"Data")),对于那些不在Request.CookiesRequest.FormRequest.QueryString或者Request.ClientCertificate中的项目,隐含就指向了Request.ServerVariables变量,而这些变量要比其他集合对象慢得多。

技巧18:调整Web服务器

  有几个IIS调整参数可以提高站点性能。比如,对于IIS4.0,我们经常发现提高ASP ProcessorThreadMax参数能够产生重大的效果,特别是在那些要等待后台资源比如数据库或中间件产品的站点。在IIS5.0中,你可以发现调整ASP线程通道要比调整AspProcessorThreadMax效果更佳。

最佳的配置设定取决于应用程序代码、支持的硬件设备以及客户端的工作量。发现最佳配置的唯一方法就是测试。

相关参考资源

Optimizing ASP scripts
Tuning IIS
ADO and SQL Server
ASP components and threading models
Dictionary components
Session state
Performance and scalability
Tools
Books
ASP Web sites
ASP style
XML

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值