找回密码
 入学

QQ登录

只需一步,快速开始

查看: 1821|回复: 6

ASP实用技巧28则

[复制链接]
发表于 2006-4-11 14:11:40 | 显示全部楼层 |阅读模式
Len Cardinal - Microsoft Consulting Services 高级顾问<BR>George V. Reilly - Microsoft IIS Performance 主管 <BR>更新时间:2000年4月 <BR>根据 Nancy Cluts 的文章(英文)改写<BR>Nancy Cluts - 开发人员技术工程师<BR>Microsoft Corporation <BR><BR>摘要:本文提供了优化 ASP 应用程序和 VBScript 的技巧。 <BR><BR>目录<BR><BR>简介<BR><BR>技巧 1:在 Web 服务器上缓存常用数据 <BR><BR>技巧 2:在 Application 或 Session 对象中缓存常用数据 <BR><BR>技巧 3:在 Web 服务器磁盘上缓存数据和 HTML <BR><BR>技巧 4:避免在 Application 或 Session 对象中缓存非灵活组件 <BR><BR>技巧 5:不要在 Application 或 Session 对象中缓存数据库连接 <BR><BR>技巧 6:妙用 Session 对象 <BR><BR>技巧 7:在 COM 对象中封装代码 <BR><BR>技巧 8:晚点获取资源,早点释放资源 <BR><BR>技巧 9:进程外的执行将牺牲可靠性 <BR><BR>技巧 10:显式使用选项 <BR><BR>技巧 11:在子例程和函数中使用局部变量 <BR><BR>技巧 12:将常用数据复制到脚本变量 <BR><BR>技巧 13:避免重新定义数组 <BR><BR>技巧 14:使用响应缓冲 <BR><BR>技巧 15:批处理内嵌脚本和 Response.Write 语句 <BR><BR>技巧 16:在开始长时间的任务之前先使用 Response.IsClientConnected <BR><BR>技巧 17:使用 &lt;OBJECT&gt; 标记实例化对象 <BR><BR>技巧 18:使用 ADO 对象和其他组件的 TypeLib 绑定 <BR><BR>技巧 19:利用浏览器的验证能力 <BR><BR>技巧 20:在循环中避免字符串串联 <BR><BR>技巧 21:启用浏览器和代理缓存 <BR><BR>技巧 22:尽可能使用 Server.Transfer 替代 Response.Redirect <BR><BR>技巧 23:在目录 URL 尾部加斜线 <BR><BR>技巧 24:避免使用服务器变量 <BR><BR>技巧 25:升级为最新的和最好的版本 <BR><BR>技巧 26:调整 Web 服务器 <BR><BR>技巧 27:进行性能测试 <BR><BR>技巧 28:读取资源链接 <BR><BR><BR><BR><BR>简介 <BR><BR>性能是一个特性。您需要预先设计性能,或是在日后重新编写应用程序。换句话说,什么是最大限度优化 Active Server Pages (ASP) 应用程序性能的好策略?<BR><BR>本文为优化 ASP 应用程序和“Visual Basic(R) 脚本编辑器 (VBScript)”提供了许多技巧。对许多陷阱和缺陷进行了讨论。本文所列的建议均在 http://www.microsoft.com 及其他站点上进行了测试,而且工作正常。本文假定您对 ASP 开发有基本的理解,包括对 VBScript 和/或 JScript、ASP Application、ASP Session 和其他 ASP 内部对象(请求、响应和服务器)。<BR><BR>ASP 的性能,通常不止取决于 ASP 代码本身。我们并不想在一篇文章中囊括所有的至理名言,只在最后列出与性能相关的资源。这些链接包括 ASP 和非 ASP 主题,包括“ActiveX(R) 数据对象 (ADO)”、“部件对象模型 (COM)”、数据库和“Internet 信息服务器 (IIS)”配置。这些是我们喜欢的链接 - 务请关注它们。<BR><BR>技巧 1:在 Web 服务器上缓存常用数据 <BR><BR>典型的 ASP 页从后端数据库检索数据,然后将结果转换为超文本标记语言 (HTML)。无论数据库的速度如何,从内存检索数据要比从后端数据库检索数据快得多。从本地硬盘读取数据通常也要比从数据库检索数据快得多。因此,通常可以通过在 Web 服务器(在内存或磁盘)上缓存数据来改善性能。<BR><BR>缓存是典型的空间与时间的折衷。如果恰当地缓存数据,您将看到性能会有惊人的提高。为使缓存发挥效力,它必须保持经常重用的数据,而且重新计算这些数据的代价是昂贵的或比较昂贵的。如果缓存充满了垃圾数据,则是对存储器的浪费。<BR><BR>不经常变化的数据也是缓存的候选数据,因为您无须担心数据与数据库的同步问题。组合框、引用表、DHTML 碎片、可扩展标记语言 (XML) 字符串、菜单项和站点配置变量(包括数据源名称 (DSN)、Internet 协议 (IP) 地址和 Web 路径)都是缓存的候选数据。注意,您可以缓存数据的表示而不是数据本身。如果 ASP 页不经常更改,而且缓存的成本也非常高(例如,整个产品目录),请考虑预先生成 HTML,而不是在每次请求时重新绘制。<BR><BR>数据应缓存在何处,有哪些缓存策略?数据经常缓存在 Web 服务器内存或 Web 服务器磁盘上。下面两个技巧讨论这些选项。<BR><BR>技巧 2:在 Application 或 Session 对象中缓存常用数据 <BR><BR>ASP Application 和 Session 对象为在内存中缓存数据提供了方便的容器。既可以将数据赋予 Application 对象,也可将数据赋予 Session 对象,这些数据在 HTTP 调用中将保留在内存中。Session 数据按用户存储,而 Application 数据在所有用户间共享。<BR><BR>何时将数据载入 Application 或 Session?通常,在 Application 或 Session 启动时加载数据。要在 Application 或 Session 启动时加载数据,请在下面两函数中添加相应的代码:Application_OnStart() 或 Session_OnStart()。这两个函数应该位于 Global.asa;如果没有,可以添加这些函数。也可以在第一次需要数据时加载数据。要进行上述操作,请在 ASP 页中添加一些代码(或编写可重用的脚本函数),这些代码检查数据是否存在,并在数据不存在时加载数据。这是称为迟缓计算的经典性能技术的例子 - 在您的确需要它之前,不进行计算。请看例子:<BR><BR>&lt;%<BR>Function GetEmploymentStatusList<BR>   Dim d<BR>   d = Application("EmploymentStatusList")<BR>   If d = "" Then<BR>      ' FetchEmploymentStatusList 函数(不显示)<BR>      ' 从 DB 中取出数据,返回数组<BR>      d = FetchEmploymentStatusList()<BR>      Application("EmploymentStatusList") = d<BR>   End If<BR>   GetEmploymentStatusList = d<BR>End Function<BR>%&gt;<BR><BR>可以为每一块所需的数据编写类似的函数。<BR><BR>数据应该以什么格式存储?任何变量类型均可存储,因为所有脚本变量是各不相同的。例如,可以存储字符串、整型或数组。通常,您将以这些变量类型之一存储 ADO 记录集的内容。若要获取 ADO 记录集衍生的数据,可以手工将数据复制到 VBScript 变量中,每次一个字段。使用一个 ADO 记录集保留函数 GetRows()、GetString() 或 Save() (ADO 2.5),会更快更简便。完整而详细的内容已超出了本文的范围。下面的演示函数使用了 GetRows() 来返回记录集数据的数组:<BR><BR>' 取记录集,以数组返回<BR>Function FetchEmploymentStatusList<BR>   Dim rs <BR>   Set rs = CreateObject("ADODB.Recordset")<BR>   rs.Open "select StatusName, StatusID from EmployeeStatus", _<BR>           "dsn=employees;uid=sa;pwd=;"<BR>   FetchEmploymentStatusList = rs.GetRows() ' 以数组返回数据<BR>   rs.Close<BR>   Set rs = Nothing<BR>End Function<BR><BR>对上面示例的进一步改进应当是缓存该列表的 HTML,而不是缓存数组。下面是一个简单的范例:<BR><BR>' 取记录集,以“HTML 选项”列表返回<BR>Function FetchEmploymentStatusList<BR>   Dim rs, fldName, s<BR>   Set rs = CreateObject("ADODB.Recordset")<BR>   rs.Open "select StatusName, StatusID from EmployeeStatus", _<BR>           "dsn=employees;uid=sa;pwd=;"<BR>   s = "&lt;select name=""EmploymentStatus"&gt;" &amp; vbCrLf<BR>   Set fldName = rs.Fields("StatusName") ' ADO 字段绑定<BR>   Do Until rs.EOF<BR>     ' 下面一行违背了不要进行字符串连接,<BR>     ' 但这是可以的,因为我们正在建立高速缓存<BR>     s = s &amp; " &lt;option&gt;" &amp; fldName &amp; "&lt;/option&gt;" &amp; vbCrLf<BR>     rs.MoveNext<BR>   Loop<BR>   s = s &amp; "&lt;/select&gt;" &amp; vbCrLf<BR>   rs.Close<BR>   Set rs = Nothing ' 参见尽早释放<BR>   FetchEmploymentStatusList = s ' 以字符串返回数据<BR>End Function<BR><BR>在正常的情况下,可以在 Application 或 Session 作用域中缓存 ADO 记录集本身。有两个警告: <BR><BR>ADO 必须为标记的自由线程 <BR>必须使用断开连接的记录集。 <BR>如果不能保证满足这两个要求,请不要缓存 ADO 记录集。在下面的非灵活组件和不要缓存连接技巧中,我们将讨论在 Application 或 Session 作用域中存储 COM 对象的危险。<BR><BR>如果在 Application 或 Session 作用域中存储数据,这些数据将一直保留在那儿,直到在程序中改变它、Session 过期或 Web 应用程序重新启动时为止。数据需要更新如何处理?若要用手工强制更新应用程序数据,可以调用只允许管理员访问的数据更新 ASP 页。另外,还可以通过函数,周期地自动刷新数据。下面的示例存储带缓存数据的时间戳,在指定时间间隔后刷新数据。<BR><BR>&lt;%<BR>' 未显示错误处理...<BR>Const UPDATE_INTERVAL = 300 ' 刷新时间间隔,以秒计<BR><BR>' 函数返回雇佣状态列表<BR>Function GetEmploymentStatusList<BR>   UpdateEmploymentStatus<BR>   GetEmploymentStatusList = Application("EmploymentStatusList")<BR>End Function<BR><BR>' 定期更新缓存的数据<BR>Sub UpdateEmploymentStatusList<BR>   Dim d, strLastUpdate<BR>   strLastUpdate = Application("LastUpdate")<BR>   If (strLastUpdate = "") Or _<BR>         (UPDATE_INTERVAL  DateDiff("s", strLastUpdate, Now)) Then<BR><BR>      ' 注意:此处可能有两个或多个调用。这是可以的,只不过<BR>      ' 产生几个不必要的取指令罢了(就此有一个工作区)<BR><BR>      ' FetchEmploymentStatusList 函数(不显示)<BR>      ' 从 DB 中取数据,返回一个数组<BR>      d = FetchEmploymentStatusList()<BR><BR>      ' 更新 Application 对象。用 Application.Lock()<BR>      ' 来确保一致的数据<BR>      Application.Lock<BR>      Application("EmploymentStatusList") = d<BR>      Application("LastUpdate") = CStr(Now)<BR>      Application.Unlock<BR>   End If<BR>End Sub<BR><BR>其他示例,请参阅具有 Application 数据的最快列表框(英文)。<BR><BR>请注意,在 Session 或 Application 对象中缓存大型数组并非上策。在访问数组元素之前,脚本语言的语法要求建立整个数组的临时副本。例如,如果在 Application 对象中缓存了将美国邮政编码映射到本地气象站的字符串数组,该字符串数组有 100,000 个元素,ASP 在找出一个字符串之前,必须将所有 100,000 个气象站复制到临时数组中。在这种情况下,建立带自定义方法的自定义组件,来存储气象站 - 或使用一个字典组件,也许更好。<BR><BR>请不要在倒洗澡水时把孩子一同倒掉,对这种观点的一个新的注解是:数组提供了对内存中相邻关键-数据对的快速查找和存储。索引字典比索引数组要慢。您应该根据具体情况选择能够提供最佳性能的数据结构。<BR><BR>技巧 3:在 Web 服务器磁盘上缓存数据和 HTML <BR><BR>有时,数据过多不能在内存中进行缓存。“过多”是一种定性的判断;它取决于打算消耗的内存量,还有缓存项的数量和这些项的检索频率。总之,如果有过多的数据要在内存中缓存,请考虑以文本或 XML 文件的形式,在 Web 服务器的硬盘上缓存数据。可以将在磁盘上缓存数据和在内存中缓存数据组合起来,为站点建立最优的缓存策略。<BR><BR>注意,在度量单个 ASP 页的性能时,在磁盘上检索数据不一定比从数据库中检索数据快。但是,缓存减轻了数据库和网络的负荷。在高负荷情况下,这将明显提高总体通信量。在查询成本很高时缓存查询的结果,缓存便非常有效,例如多表联合或复杂的存储过程,或缓存大型的结果集。按照惯例,测试竞争方案。<BR><BR>ASP 和 COM 提供了几种构建磁盘缓存方案的工具。ADO 记录集的 Save() 和 Open() 函数,保存和加载磁盘上的记录集。您可以使用这些方法重写上面 Application 数据缓存技巧中的范例代码,用 Save() 文件替换向 Application 对象写入数据的代码。<BR><BR>还有其他一些处理文件的组件: <BR><BR>Scripting.FileSystemObject 使您能够创建、读取和写入文件。 <BR>MSXML 是随 Internet Explorer 提供的 Microsoft(R) XML 解析器,它支持保存和加载 XML 文档。 <BR>LookupTable 对象(在 MSN 上使用的范例)是从磁盘加载简单列表的良好选择。 <BR>最后,请考虑在磁盘上缓存数据的表示,而不是数据本身。预制的 HTML 可以作为 .htm 或 .asp 文件存储在磁盘上;超级链接可以直接指向这些文件。可以使用商业工具,如 XBuilder 或 Microsoft(R) SQL Server 的 Internet 发行功能来自动化 HTML 生成过程。另外,可以将 HTML 片段 #include 到 .asp 文件。还可以使用 FileSystemObject 从磁盘读取 HTML 文件或使用 XML 进行早期调整(英文)。<BR><BR>技巧 4:避免在 Application 或 Session 对象中缓存非灵活组件 <BR><BR>虽然在 Application 或 Session 对象中缓存数据是个好主意,但是缓存 COM 对象可能有严重缺陷。将常用 COM 对象嵌入 Application 或 Session 对象通常具有吸引力。遗憾的是,很多 COM 对象,包括用 Visual Basic 6.0 或更早版本编写的 COM 对象,在 Application 或 Session 对象中存储时将导致严重的瓶颈。<BR><BR>特别是任何非灵活组件,在 Session 或 Application 对象中缓存时将导致性能瓶颈。灵活组件是标记为 ThreadingModel=Both 的组件(它聚集了自由线程汇集器 (FTM))或标记为 ThreadingModel=Neutral 的组件(Windows(R) 2000 和 COM+ 中新增的“中性”模型。)下列组件是非灵活的: <BR><BR>自由线程组件(除非它们聚集了 FTM)。 <BR>单元线程组件。 <BR>单线程组件。 <BR>已配置组件(Microsoft Transaction Server (MTS)/COM+ 库和服务器包/应用程序)为非灵活组件,除非它们是“中性”线程的。单元线程组件和其他非灵活组件最适于在页作用域工作(也就是说,它们在单个 ASP 页上创建和销毁)。<BR><BR>在 IIS 4.0 中,标记为 ThreadingModel=Both 的组件被视为灵活的。在 IIS 5.0 中,这已经不够了。组件不仅必须标记为 Both,而且还必须聚集 FTM。灵活性文章说明了如何使得用“活动模板库”编写的 C++ 组件聚集 FTM。请注意,如果组件缓存接口指针,这些指针本身必须为灵活的、或者必须存储在“COM 全局接口表 (GIT)”中。如果不能重新编译 Both 线程组件,使它聚集 FTM,则可以将该组件标记为 ThreadingModel=Neutral。另外,如果不希望 IIS 进行灵活性检查(这样,希望非灵活组件能够存储在 Application 或 Session 作用域中),可以在 metabase 中设置 AspTrackThreadingModel 为 True。不主张更改 AspTrackThreadingModel。<BR><BR>如果试图在 Application 对象中存储用 Server.CreateObject 创建的非灵活组件,IIS 5.0 将产生错误。可以通过在 Global.asa 中使用 &lt;object runat=server scope=application ...&gt; 解决该问题,但是不主张这样做,因为这将导致汇集和串行化,说明如下。<BR><BR>如果缓存非灵活组件,会发生什么错误呢?缓存在 Session 对象中的非灵活组件,将把会话“锁定”到某个 ASP 工作器线程。ASP 维护着一个工作器线程池,它向请求提供服务。通常,新的请求由第一个可用的工作器线程来处理。如果 Session 被锁定到某个线程,则该请求将不得不等待它所关联的线程变为可用。打个比方:您进入一个超市,挑选了一些食品,然后在第 3 号收款台交款。从这以后,每当您在这个超市购买食品,都不得不始终在第 3 号收款台交款,即使是在其他收款台人少或没人时。<BR><BR>将非灵活组件存储在 Applicaton 作用域甚至会对性能产生更严重的影响。ASP 将不得不创建专用的线程来运行非灵活的、Applicaton 作用域内的组件。这将导致两种后果:所有调用不得不被汇集到该线程,而且所有调用被串行化。汇集意味着:参数不得不存储在内存的共享区;对该专用线程执行昂贵的上下文切换;组件的方法被执行;结果汇集到共享区域;以及经过另一个昂贵的上下文切换,使控制权返回原来的线程。串行化意味着所有方法必须一个挨一个地运行(同一时刻只能运行一个方法)。两个不同的 ASP 工作器线程不可能同时执行共享组件上的方法。这将扼杀并行机制,尤其是在多处理器计算机上。更坏的是,所有非灵活的、Application 作用域内的组件都将共享一个线程(“Host STA”),所以串行化的影响更加严重。<BR><BR>是否感到困惑?下面我们提出几个通用规则。如果您正在用 Visual Basic (6.0) 或更早版本编写对象,请不要将它们缓存在 Application 或 Session 对象中。如果您不知道对象的线程模型,就不要缓存它。不要缓存非灵活对象,而应当在每页上创建并释放它们。对象将直接运行在 ASP 工作器线程上,这样,将不会发生汇集或串行化。如果 COM 对象正运行在 IIS 框中,而且如果它们没有花很长时间来初始化和取消,性能将是足够的。注意,不要用该方法使用单线程对象。小心:VB 可以创建单线程的对象!如果您必须以该方式使用单线程的对象(如 Microsoft Excel 电子表格),则不要期望有很高的吞吐量。<BR><BR>当 ADO 被标记为自由线程时,则缓存 ADO 记录集是安全的。要将 ADO 标记为自由线程,请使用 Makfre15.bat 文件,该文件通常位于如下目录中:\Program Files\Common\System\ADO。<BR><BR>警告: 如果您正在用 Microsoft Access 作为数据库,则不应当将 ADO 标记为自由线程。通常,ADO 记录集还必须是断开连接的,如果您不能控制站点的 ADO 配置(例如,您是独立的软件厂商 [ISV],将 Web 应用程序卖给客户,然后由他们来管理他们自己的配置),那么不缓存记录集可能会更好。<BR><BR>词典组件也是灵活对象。LookupTable 从数据文件加载它的数据,并且它对组合框数据和配置信息是有用的。来自 Duwamish Books 的 PageCache 对象提供了目录语义,和 Caprock Dictionary 的表现一样。这些对象或它们的派生对象可以构成有效缓存策略的基础。注意,Scripting.Dictionary 对象不是灵活的,所以不应当存储在 Application 或 Session 作用域。<BR><BR>技巧 5:不要在 Application 或 Session 对象中缓存数据库连接 <BR><BR>缓存 ADO 连接通常是不好的策略。如果一个 Connection 对象存储在 Application 中,并在所有页上使用,那么所有页将竞争使用该连接。如果 Connection 对象存储在 ASP Session 对象中,那么将为每个用户创建数据库连接。这将连接池的好处毁于一旦,并对 Web 服务器和数据库产生不必要的压力。<BR><BR>取代缓存数据库连接的方法是,在每个使用 ADO 的 ASP 页上创建并取消 ADO 对象。这是个有效的方法,因为 IIS 具有内置的数据库连接池。更准确的说,IIS 自动启用 OLEDB 和 ODBC 连接池。这确保了创建并取消每个页上的连接将是有效的。<BR><BR>由于被连接的记录集中存储有对数据库连接的引用,所以,不应当在 Application 或 Session 对象中缓存被连接的记录集。但是,可以安全地缓存断开连接的记录集,因为它不包含对其数据连接的引用。要断开记录集的连接,请执行如下两个步骤:<BR><BR>    Set rs = Server.CreateObject("ADODB.RecordSet")<BR>    rs.CursorLocation = adUseClient  ' 第 1 步<BR><BR>    ' 植入带数据的记录集<BR>    rs.Open strQuery, strProv<BR><BR>    ' 现在断开记录集同数据提供者和数据源的连接<BR>    rs.ActiveConnection = Nothing    ' 第 2 步<BR><BR>有关连接池的详细信息,请参阅 ADO 和 SQL Server(英文)引用。<BR>
 楼主| 发表于 2006-4-11 14:12:01 | 显示全部楼层
技巧 6:妙用 Session 对象 <BR><BR>在肯定了在 Applications 和 Sessions 中缓存的优点之后,我们建议您避免使用 Session 对象。下面将会谈到,当用于忙碌站点时,Sessions 有几个缺点。所谓忙碌,通常是指站点每秒请求数百页或同时有数千个用户。该技巧对于必须进行水平扩展的站点,即那些利用多个服务器来适应负载或执行容错功能的站点来说,更加重要。对于较小的站点,如 intranet 站点,Sessions 的便利,与开销相比也是值得的。<BR><BR>为了翻新,ASP 自动为每个访问 Web 服务器的用户创建一个 Session。每个 Session 有大约 10 KB 内存开销(在存储在 Session 中的任何数据中是最高的),并使所有的请求都慢了一点。Session 一直保持活动状态,直到达到可配置的超时(通常 20 分钟)为止。<BR><BR>Session 最大的问题不是性能而是可伸缩性。Session 不能跨越 Web 服务器;一旦在一个服务器上创建了 Session,它的数据就保持在那里。这意味着,如果您在 Web 领域中使用 Sessions,您将不得不为每个用户的请求设计一种策略,以便始终将这些请求引向用户的 Session 所在的服务器。这被称为将用户“粘”到 Web 服务器上。术语“粘性会话”即来源于此。由于 Session 没有保持到磁盘上,所以,当 Web 服务器崩溃时,被“粘住”的用户将丢失他们的 Sessions 状态。<BR><BR>用于实施粘性会话的策略包括硬件和软件解决方案。如 Windows 2000 Advanced Server 中的网络负载平衡解决方案和 Cisco 公司的“本地指向器”解决方案可以实施粘性会话,但以牺牲一些可伸缩性为代价。这些解决方案并不完美。我们不主张您现在全盘推翻您的软件解决方案(我们过去常用 ISAPI 筛选器和 URL 矫直对方案进行检查)。<BR><BR>Application 对象也不能跨越服务器;如果您需要在 Web 领域内共享并更新 Application 数据,则需要使用后端数据库。但只读的 Application 数据在 Web 领域中仍然有用。<BR><BR>如果只是为了增加正常运行时间(用于处理故障转移和服务器维护),大多数执行重要任务的站点将需要部署至少两台 Web 服务器。所以,在设计执行重要任务的应用程序时,您将需要实施“粘性会话”,或者简单地避开 Sessions 以及其他任何在单个 Web 服务器上存储用户状态的状态管理技术。<BR><BR>如果当前没有使用 Sessions,请确保将它们关闭。可以通过“Internet 服务管理器”(请参阅 ISM 文档)来为应用程序执行该操作。如果决定使用 Sessions,可以采取几个方法来将对性能的影响降低到最小。<BR><BR>可以将不需要 Sessions 的内容(如“帮助”屏幕、访问者区域等)移动到关闭了 Sessions 的、单独的 ASP 应用程序中。可以逐页提示 ASP:在给定的页中您不需要 Session 对象;使用位于 ASP 页顶端的如下指令:<BR><BR>&lt;% @EnableSessionState=False %&gt;<BR><BR>使用该指令的一个很好的原因是,Session 给框架集带来了有趣的问题。ASP 保证任何时候只执行一个来自 Session 的请求。这样可以确保如果浏览器为一个用户请求了多个页时,在每一时刻只有一个 ASP 请求将进入 Session;这就避免了在访问 Session 对象时出现多线程问题。遗憾的是,结果,框架集中的所有页均被以串行化方式绘制,一个接一个地,而不是同时地。这样,用户可能不得不等待很长时间才能得到所有框架内容。这意味着:如果某些框架页不信任 Session,一定要使用 @EnableSessionState=False 指令告诉 ASP。<BR><BR>作为使用 Session 对象的替代方式,有很多方法可以用来管理 Session 状态。对于状态数量较小的情况(不到 4 KB),通常建议使用 Cookies、QueryString 变量和隐藏形式的变量。对于较大数量的数据,如购物推车,则使用后端数据库是最合适的选择。关于在 Web 服务器领域中的状态管理技术已经有很多资料。详细信息,请参阅 会话状态(英文)。<BR><BR>技巧 7:在 COM 对象中封装代码 <BR><BR>如果您有很多 VBScript 或 JScript,那么您可以通过把代码移动到已编译的 COM 对象来经常改进它们的性能。已编译的代码通常比被解释代码运行得更快。已编译的 COM 对象可以通过“早期绑定”访问其他 COM 对象,这种调用 COM 对象方法的手段,比脚本所使用的“后期绑定”更有效。<BR><BR>将代码封装在 COM 对象种有如下好处(超越性能): <BR><BR>COM 对象是将表达逻辑与业务逻辑分隔开来的好办法。 <BR>COM 对象启用了代码重用。 <BR>很多开发商发现,用 VB、C++ 或 Visual J++ 书写的代码,比 ASP 更容易调试。 <BR>COM 对象有一些缺点,包括初始开发时间以及需要不同的编程技巧。需要警告您的是,封装“少”量的 ASP 可能会导致性能降低,而不是提高。通常,在少量 ASP 代码封装到 COM 对象时出现这样的情况。这时候,创建和调用 COM 对象的开销,超过了已编译代码的好处。至于 ASP 脚本和 COM 对象代码怎样合并才能产生最佳性能还有待测试。注意,与 Windows NT(R) 4.0/IIS 4.0 相比,Microsoft 已经在 Windows 2000/IIS 5.0 中极大地提高了脚本和 ADO 性能。这样,已编译代码对 ASP 代码的性能优势已经随着 IIS 5.0 的引入而降低。<BR><BR>有关在 ASP 中使用 COM 对象的优缺点的更多讨论,请参阅 ASP 组件准则和用 COM 和 Microsoft Visual Basic 6.0 对分布式应用程序进行编程(英文)。如果您的确部署了 COM 组件,要对它们进行强度测试是非常重要的。实际上,所有 ASP 应用程序都应当作为正式过程进行强度测试。<BR><BR>技巧 8:晚点获取资源,早点释放资源 <BR><BR>这是个小技巧。通常,最好晚点获取资源而要早点释放资源。这些资源包括 COM 对象、文件句柄和其他资源。<BR><BR>ADO 连接和记录集是这种优化的首要目标。当您使用完记录集,就是说用它的数据打印完一个表格后,请立即将它释放,而不是等到页的末尾。将您的 VBScript 变量设置为 Nothing 是最好的做法。不要让记录集简单地脱离作用域。同时,应当释放任何有关的 Command 或 Connection 对象。(不要忘了对记录集或“连接”调用 Close(),在将它们设置为 = Nothing 之前。)这将缩短数据库必须为您调整资源的时间跨度,并将数据库连接尽可能快地释放给连接池。<BR><BR>技巧 9:进程外的执行将牺牲可靠性 <BR><BR>ASP 和 MTS/COM+ 都有允许您以可靠性换取性能的配置选项。当建立和部署应用程序时,应当理解这种交换。<BR><BR>ASP 选项 <BR><BR>ASP 应用程序可以配置为以三种方式之一运行。在 IIS 5.0 中引入了术语“隔离级”来描述这些选项。三个隔离级值分别是低、中和高: <BR><BR>低级隔离。该隔离级在所有版本的 IIS 中受到支持,并且是最快的。它在主 IIS 进程 Inetinfo.exe 中执行 ASP。如果 ASP 应用程序崩溃,则 IIS 也将崩溃。(要在 IIS 4.0 下重新启动 IIS,Web 站点管理员需要使用工具,如 InetMon,来监视站点,如果服务器失败,将运行批处理文件来重新启动服务器。而 IIS 5.0 则引入了可靠的重新启动,它将自动重新启动失败的服务器。) <BR>中级隔离。IIS 5.0 引入了这个新隔离级,它称为进程外的,这是因为 ASP 运行在 IIS 进程之外。在中级隔离中,所有被配置按“中级”运行的 ASP 应用程序,将共享单个进程空间。这将减少在一个服务器上运行多个进程外的 ASP 应用程序所需的进程数。中级是 IIS 5.0 中默认的隔离级。 <BR>高级隔离。在 IIS 4.0 和 IIS 5.0 中受到支持,高级隔离也是进程外的。如果 ASP 崩溃,则 Web 服务器并不崩溃。ASP 应用程序将在下一个 ASP 请求时自动重新启动。使用高级隔离,每个被配置为按高级运行的 ASP 应用程序,将在其自己的进程空间中运行。这样可以保护 ASP 应用程序彼此不受干扰。它的缺点是它需要为每个 ASP 应用程序建立独立的进程。当需要在一个服务器上主持十多个应用程序时,会增加很多开销。 <BR>那么,哪个选项是最好的呢?在 IIS 4.0 中,运行进程外的应用程序会极大地影响性能。在 IIS 5.0 中,做了许多工作,使得进程外运行 ASP 应用程序对性能产生的影响降到了最低。实际上,在大多数测试中,在 IIS 5.0 中的 ASP 进程外应用程序,要比 IIS 4.0 中的进程内应用程序运行得更快。无论如何,进程内(低隔离级)在两种平台上仍然产生了最好的性能。但是,如果您的命中率相对较低或最大吞吐量较低,选择低隔离级不会有太大的好处。所以,除非您需要每个 Web 服务器每秒处理数百或数千个页面,否则没有必要选择低隔离级。同样,应当测试多种配置并判断哪种情形最适合您。<BR><BR>注意: 当您进程外运行 ASP 应用程序(中级或高级隔离)时,则在 NT4 上它们将运行在 MTS 中,而在 Windows 2000 上它们将运行在 COM+ 中。即,在 NT4 上它们运行在 Mtx.exe 中,而在 Windows 2000 上它们运行在 DllHost.exe 中。在“任务管理器”中,您可以看见这些正在运行的进程。还可以看见 IIS 如何为进程外的 ASP 应用程序配置 MTS 程序包或 COM+ 应用程序。<BR><BR>COM 选项 <BR><BR>COM 组件也有三个配置选项,虽然与 ASP 选项不完全相似。COM 组件可以被:“不配置”、配置为“库应用程序”或配置为“服务器应用程序”。“不配置”是指不向 COM+ 注册组件。组件将运行在调用者的进程空间,就是说,它们是“进程中”的。“库应用程序”也是进程中的,但受惠于 COM+ 的服务,包括安全性、事务和环境支持。“服务器应用程序”被配置为在其自己的进程空间中运行。<BR><BR>您可能看到,不配置的组件比库应用程序优点稍微多些。您还可能看到“库应用程序”比“服务器应用程序”有很大的性能优点。这是因为“库应用程序”与 ASP 运行在同一个进程中,而“服务器应用程序”则运行在自己的进程中。内部进程调用的开销要比进程内调用的开销大得多。而且,当在进程之间传递数据(如记录集)时,必须在两个进程之间复制所有的数据。<BR><BR>缺点!当使用“COM 服务器应用程序”时,如果要在 ASP 和 COM 之间传递对象,请确保对象实现“按值汇集”,即 MBV。实现 MBV 的对象将其自身从一个进程复制到另一个进程。这比另一种方式好,在另一种方式中,对象留在创建它的进程中,而其他进程则重复调用创建使用该对象的进程。被断开连接的 ADO 记录集将是按值汇集的,已连接的记录集则不是。Scripting.Dictionary 并不实现 MBV,不会在进程之间传递。最后,要另外告诉 VB 程序员的是:MBV 不是通过传递参数ByVal 获得的。MBV 是由原始组件创作者实现的。<BR><BR>怎么办? <BR><BR>如果您想要以性能与可靠性的合理交换来完成您的配置,我们的推荐如下: <BR><BR>在 IIS 4.0 上,使用 ASP 的低隔离级别,并使用“MTS 服务器包”。 <BR>在 IIS 5.0 上,使用 ASP 的中隔离级别,并使用“COM+ 库应用程序”。 <BR>这些是很一般的准则;通常让公司以中或高隔离级别运行 ASP,而单一目的的 Web 服务器可运行于低隔离级别。请权衡折中并自行决定满足需求的配置。<BR><BR>技巧 10:显式使用选项 <BR><BR>在 .asp 文件中显式使用选项 Explicit。置于 .asp 文件开头的这一指令,强制开发人员声明所有要使用的变量。许多开发人员认为这有助于调试应用程序,因为它避免了错误键入变量名称而不经意地新建变量(例如,MyXLMString=... 而非 MyXMLString=)。<BR><BR>也许更重要的是,声明的变量比未声明的变量快。实际上,脚本运行时,在每次使用未声明变量时按照名称引用。而声明的变量,在编译或运行时分配了序号。这样,声明的变量按照该序号引用。由于选项 Explicit 强制变量声明,因此保证声明了所有变量而实现快速访问。<BR><BR>
回复

使用道具 举报

 楼主| 发表于 2006-4-11 14:12:24 | 显示全部楼层
技巧 11:在子例程和函数中使用局部变量 <BR><BR>局部变量是在子例程和函数中声明的变量。在子例程和函数中,局部变量访问要快于全局变量访问。使用局部变量还可以使代码更加清晰,因此尽可能使用局部变量。<BR><BR>技巧 12:将常用数据复制到脚本变量 <BR><BR>在 ASP 中访问 COM 时,应该将常用的对象数据复制到脚本变量中。这将削减 COM 方法的调用,COM 方法的调用与访问脚本变量相比,要相对昂贵些。在访问 Collection 和 Dictionary 对象时,这一技术也可以削减了昂贵的查找。<BR><BR>通常,如果打算多次访问对象数据,请将数据放入脚本变量。该优化的主要目标是 Request 变量(Form 和 QueryString 变量)。例如,您的站点可能传递一个名为 UserID 的 QueryString。假定该 UserID 变量要在特定页中引用 12 次。请不要调用 Request("UserID") 12 次,而在 ASP 页的开头将 UserID 赋予某个变量。然后就在页中使用该变量。这将节省 11 次 COM 方法调用。<BR><BR>在实际中,访问 COM 属性或方法暗藏着繁复的过程和大量的开销。下面是一个示例,它只是些相当普通的代码(从语法上讲):<BR><BR>Foo.bar.blah.baz = Foo.bar.blah.qaz(1)<BR>If Foo.bar.blah.zaq = Foo.bar.blah.abc Then ' ...<BR><BR>在运行这段代码时,将发生下列事件: <BR><BR>变量 Foo 被解析为全局变量。 <BR>变量 bar 被解析为 Foo.的成员。这将产生 COM 方法调用。 <BR>变量 blah 被解析为 Foo.bar 的成员。这也将产生 COM 方法调用。 <BR>变量 qaz 被解析为 foo.bar.blah 的成员。是的,这也将产生 COM 方法调用。 <BR>调用 Foo.bar.blah.quaz(1)。又一次产生 COM 方法调用。理解这幅图了吗? <BR>执行步骤 1 到 3 将再次解析 baz。系统不知道调用 qaz 是否更改对象模型,因此步骤 1 到 3 必须再次执行解析 baz。 <BR>将 baz 解析为 Foo.bar.blah 的成员。进行属性置入。 <BR>再次执行步骤 1 到 3 并解析 zaq。 <BR>再次执行步骤 1 到 3 并解析 abc。 <BR>正如所见,这是非常可怕的低效率(而且非常慢)。用 VBScript 编写该代码实现的快速方法为:<BR><BR>Set myobj = Foo.bar.blah ' 对 blah 做一次解析<BR>Myobj.baz = myobj.qaz(1)<BR>If Myobj.zaq = Myobj.abc Then '...<BR><BR>如果您使用的是 VBScript 5.0 或更高版本,则可用 With 语句来写这段代码:<BR><BR>With Foo.bar.blah<BR>    .baz = .qaz(1)<BR>    If .zaq = .abc Then '...<BR>    ...<BR>End With<BR><BR>请注意该技巧对 VB 编程同样有效。<BR><BR>技巧 13:避免重新定义数组 <BR><BR>尽量避免 Redim 数组。从关心性能的角度来说,如果计算机受物理内存的限制,最好一开始将数组的维数设置为最差方案 - 而不要将维数设置为最佳方案,再根据需要重新定义维数。这并不意味着明知道不需要那么多而就是应该分配太多的内存。<BR><BR>下面代码展示了您没有必要地使用了Dim 和 Redim 来解决。<BR><BR>&lt;% <BR>Dim MyArray()<BR>Redim MyArray(2)<BR>MyArray(0) = "hello"<BR>MyArray(1) = "good-bye"<BR>MyArray(2) = "farewell"<BR>...<BR>' 一些别的代码中,这里您不需要更多的空间,然后 ...<BR>Redim Preserve MyArray(5)<BR>MyArray(3) = "more stuff"<BR>MyArray(4) = "even more stuff"<BR>MyArray(5) = "yet more stuff"<BR>%&gt;<BR><BR>更好的办法是只须一开始 Dim 数组为正确的大小(本例中为 5),而不是 Redim 数组,再加大数组。这可能会浪费一点儿内存(如果没有用尽所有元素),但是获得的是速度。<BR><BR>技巧 14:使用响应缓冲 <BR><BR>您可以通过打开“响应缓冲区”来缓冲值得输出的整个页。这将写入浏览器的数据量降为最小,从而提高总体性能。每次写入都会有大量开销(包括 IIS 和通过电缆发送的数据量),因此写入的越少越好。TCP/IP 的工作效率,在发送少量大的数据块时明显高于发送大量小的数据块时,原因在于它的低速启动和 Nagling 算法(用于最小化网络阻塞)。<BR><BR>打开响应缓冲有两种方法。第一种,可以使用“Internet 服务管理器”为整个应用程序打开响应缓冲。这是推荐的方法,在 IIS 4.0 和 IIS 5.0 中,在默认情况下,为新的 ASP 应用程序打开响应缓冲。第二种,逐页将下列代码行放在 ASP 页的开头,从而启用响应缓冲:<BR><BR>&lt;% Response.Buffer = True %&gt;<BR><BR>该行代码必须在任何响应数据写入浏览器之前执行(也就是说,在任何 HTML 出现在 ASP 脚本中之前和任何 Cookies 被使用 Response.Cookies 集合设置之前)。通常,最好是为整个应用程序打开响应缓冲。这允许省略上面每页中的代码行。<BR><BR>Response.Flush <BR><BR>响应缓冲的通病是用户感觉 ASP 页响应迟钝(尽管总体响应时间改善了),因为他们需要等到整个页生成后才能看见该页。对于长时间运行的页面,可以通过设置 Response.Buffer = False 关闭响应缓冲。但是,更好的策略是使用 Response.Flush 方法。该方法刷新由 ASP 绘入浏览器的所有 HTML。例如,绘制了具有 1,000 行的表的 100 行后,ASP 可以调用 Response.Flush 强制将结果绘制到浏览器;这允许用户在其余的行准备好之前先看到头 100 行。该技术给了您两个举世无双的好东西 - 响应缓冲与浏览器中数据的逐步显示的组合。<BR><BR>(注意,在上面 1,000 行表的示例中,许多浏览器,在看到 &lt;/table&gt; 结束标记之前不会开始绘制表。请检查目标浏览器的支持性。要解决该问题,请将表分割为具有较少行的多个表,然后在每个表后面调用 Response.Flush。新版本的 Internet Explorer 将在表完全下载之前绘制表,特别是如果指定表的列宽则绘制速度更快;这避免强制 Internet Explorer 通过度量每个单元格的内容来计算列宽。)<BR><BR>响应缓冲的另一个通病是在生成大型页时将使用服务器的大量内存。对于该问题,除了要求生成大型页的技巧外,还可以通过巧妙地使用 Response.Flush 来解决。<BR><BR>技巧 15:批处理内嵌脚本和 Response.Write 语句 <BR><BR>VBScript 语法 &lt;% = expression %&gt; 将“表达式”的值写入 ASP 输出流。如果响应缓冲没有打开,则这些语句的每一句都会导致通过网络,以许多小型包的形式,向浏览器写入数据。这是非常慢的。另外,解释少量脚本和 HTML,将导致在脚本引擎和 HTML 之间切换,也降低了性能。因此,请使用下面技巧:用对 Response.Write 的一个调用,替换内嵌的密集组合表达式。例如,在下面范例中,每行每字段有一个对响应流的写入,每行都有许多 VBScript 和 HTML 之间的切换:<BR><BR>&lt;table&gt;<BR>&lt;% For Each fld in rs.Fields %&gt;<BR>    &lt;th&gt;&lt;% = fld.Name %&gt;&lt;/th&gt;<BR>&lt;%<BR>Next <BR>While Not rs.EOF<BR>%&gt;<BR>  &lt;tr&gt;<BR>  &lt;% For Each fld in rs.Fields %&gt;<BR>     &lt;td&gt;&lt;% = fld.Value %&gt;&lt;/td&gt;<BR>   &lt;% Next <BR>  &lt;/tr&gt;<BR>   &lt;% rs.MoveNext <BR>Wend %&gt;<BR>&lt;/table&gt;<BR><BR>下面是更有效的代码,每行中有一个对响应流的写入。所有代码均包含在一个 VBScript 块内:<BR><BR>&lt;table&gt;<BR>&lt;%<BR>  For each fld in rs.Fields<BR>      Response.Write ("&lt;th&gt;" &amp; fld.Name &amp; "&lt;/th&gt;" &amp; vbCrLf)<BR>  Next<BR>  While Not rs.EOF<BR>    Response.Write ("&lt;tr&gt;")<BR>    For Each fld in rs.Fields %&gt;<BR>      Response.Write("&lt;td&gt;" &amp; fld.Value &amp; "&lt;/td&gt;" &amp; vbCrLf)<BR>    Next<BR>    Response.Write "&lt;/tr&gt;"<BR>  Wend<BR>%&gt;<BR>&lt;/table&gt;<BR><BR>当响应缓冲被禁用时,本技巧的作用更大。最好启用响应缓冲,然后观察批处理 Response.Write 是否对性能有帮助。<BR><BR>(在这一特例中,构建表的主体的嵌套循环 (While Not rs.EOF...) 可以被精心构造的、对 GetString 的调用所替代。)<BR>
回复

使用道具 举报

 楼主| 发表于 2006-4-11 14:12:37 | 显示全部楼层
技巧 16:在开始长时间的任务之前先使用 Response.IsClientConnected <BR><BR>如果用户失去耐心,他们可以在开始执行他们的请求之前放弃 ASP 页。如果他们单击了 Refresh 或跳转到服务器的其他页上,在 ASP 请求队列的末尾将有一个新的请求,而在队列的中间有一个断开连接的请求。这通常发生在服务器处于高负荷的情况下(它有一个很长的请求队列,相应的响应时间也很长),这只能使情况更糟。如果用户不再连接,将没有执行 ASP 页的点(特别是低速、重量级的 ASP 页)。可以使用 Response.IsClientConnected 属性检查这种情况。如果它返回 False,则应调用 Response.End 并放弃该页的剩余内容。实际上,每当 ASP 要执行新的请求时,IIS 5.0 便将该方法编码,来检查队列中的请求有多长。如果在那里超过了 3 秒钟,ASP 会检查客户是否仍然连接着,如果客户已断开连接,就立即结束该请求。您可以使用 metabase 中的 AspQueueConnectionTestTime 设置,调整这 3 秒的超时时间。<BR><BR>如果有某页执行了很长时间,您可能还想按一定的时间间隔检查 Response.IsClientConnected。在启用响应缓冲之后,按一定的时间间隔执行 Response.Flush,告诉用户正在进行的是哪些事情,是个好办法。<BR><BR>注意 在 IIS 4.0 中,Response.IsClientConnected 将不能正常工作,除非首先执行 Response.Write。如果启用了缓冲,也需要执行 Response.Flush。在 IIS 5.0 中则不必如此 - Response.IsClientConnected 工作得很好。在任何情况下,Response.IsClientConnected 都要有些开销,所以,只有在执行至少要用 500 毫秒(如果想维持每秒几十页的吞吐量,这是一个很长的时间了)的操作前才使用它。作为通常的规则,不要在紧密循环的每次迭代中调用它,例如当绘制表中的行,可能每 20 行或每 50 行调用一次。<BR><BR>技巧 17:使用 &lt;OBJECT&gt; 标记实例化对象 <BR><BR>如果需要引用不能在所有代码路径中使用的对象(尤其是服务器 - 或应用程序 - 作用域的对象),则使用 Global.asa 中的 &lt;object runat=server id=objname&gt; 标记来声明它们,而不是使用 Server.CreateObject 方法。Server.CreateObject 立刻创建对象。如果以后不使用那个对象,就不要浪费资源。&lt;object id=objname&gt; 标记声明了 objname,但实际上 objname 此时并没有创建,直到它的方法或属性第一次被使用时才创建。<BR><BR>这是迟缓计算的另一个例子。<BR><BR>技巧 18:使用 ADO 对象和其他组件的 TypeLib 声明 <BR><BR>当使用 ADO 时,开发人员经常包含 adovbs.txt 来获得对 ADO 不同常量的访问权。该文件必须包含在要使用这些常量的每一页中。该常量文件非常大,给每个 ASP 页增加了很多编译时间和脚本大小方面的开销。<BR><BR>IIS 5.0 提供了绑定到组件类型库的能力。允许您在每个 ASP 页上引用一次类型库并使用它。每页不需要为编译常量文件付出代价,并且组件开发人员不必为在 ASP 中的使用而生成 VBScript #include 文件。<BR><BR>要访问 ADO 类型库,请将下列语句之一放入 Global.asa 中。<BR><BR>&lt;!-- METADATA NAME="Microsoft ActiveX Data Objects 2.5 Library"<BR>              TYPE="TypeLib" UUID="" --&gt; <BR><BR>或者<BR><BR>&lt;!-- METADATA TYPE="TypeLib" <BR>              FILE="C:\Program Files\Common Files\system\ado\msado15.dll" --&gt; <BR><BR>技巧 19:利用浏览器的验证能力 <BR><BR>流行的浏览器具有对以下功能的高级支持,例如 XML、DHTML、Java 小程序以及远程数据服务。请尽量利用这些功能。所有这些技术,都可以通过执行客户端的验证和数据缓存,减少了与 Web 服务器之间的往返。如果您正在运行智能浏览器,该浏览器可以为您进行一些验证(例如,在运行 POST 之前检查信用卡的校验和否有效)。重申一次,请尽量使用这些功能。由于削减了客户端到服务器的往返路程,将减少对 Web 服务器的压力,并且削减了网络通信量(虽然发送给浏览器的初始页面可能更大),服务器访问的所有后端资源也削减了。而且用户不必经常提取新页,使用户的感受好一些。这并不减轻对服务器端验证的需要。还是应该经常进行服务器端的验证。这样能够防止由于某些原因从客户端来的坏数据,例如黑客,或者不运行客户端验证程序的浏览器。<BR><BR>许多站点由独立于浏览器创建的 HTML 组成。这一点经常阻碍开发人员利用可以提高性能的流行浏览器功能。对于真正高性能的、必须关心浏览器的站点,良好的策略是针对流行的浏览器优化您的页面。在 ASP 中使用“浏览器性能组件”,很容易检测到浏览器的功能。诸如 Microsoft FrontPage 等工具,能帮助您设计使用所希望的目标浏览器和 HTML 版本的代码。更详细的讨论,请查看 When is Better Worse? Weighing the Technology Trade-Offs(英文)。<BR>
回复

使用道具 举报

 楼主| 发表于 2006-4-11 14:13:05 | 显示全部楼层
技巧 20:在循环中避免字符串串联 <BR><BR>许多人在循环中创建类似这样的字符串:<BR><BR>s = "&lt;table&gt;" &amp; vbCrLf<BR>For Each fld in rs.Fields<BR>    s = s &amp; " &lt;th&gt;" &amp; fld.Name &amp; "&lt;/th&gt; "<BR>Next<BR><BR>While Not rs.EOF<BR>    s = s &amp; vbCrLf &amp; " &lt;tr&gt;"<BR>    For Each fld in rs.Fields<BR>        s = s &amp; " &lt;td&gt;" &amp; fld.Value &amp; "&lt;/td&gt; "<BR>    Next<BR>    s = s &amp; " &lt;/tr&gt;"<BR>    rs.MoveNext<BR>Wend<BR><BR>s = s &amp; vbCrLf &amp; "&lt;/table&gt;" &amp; vbCrLf<BR>Response.Write s<BR><BR>这种方法有几个问题。首先,重复连接字符串所花费的时间,以二次方曲线的速率增长;粗略地计算,运行循环所花费的时间,与记录数乘以字段数的平方成正比。举一个简单的例子,便能清楚地说明这一点。<BR><BR>s = ""<BR>For i = Asc("A") to Asc("Z")<BR>    s = s &amp; Chr(i)<BR>Next<BR><BR>在第一次迭代中,得到一个字符的字符串“A”。在第二次迭代中,VBScript 必须重新分配字符串并复制两个字符“AB”到 s。在第三次迭代中,它必须再次重新分配 s,并复制三个字符到 s。在第 N 次(26 次)迭代中,它必须重新分配并复制 N 个字符到 s。就是 1+2+3+...+N 的和,为 N*(N+1)/2 次复制。<BR><BR>在以上记录集的例子中,如果有 100 条记录和 5个字段,则内部的循环将执行 100*5 = 500 次,并且完成所有复制和重新分配所花费时间,将与 500*500 = 250,000 成正比。对一个大小适度的记录集,将有很多次复制。<BR><BR>在该例子中,代码可以改进:字符串的连接将被 Response.Write() 或内嵌脚本 (&lt;% = fld.Value %&gt;) 所替代。如果打开响应缓冲,这个操作将会很快,因为 Response.Write 仅仅将数据添加到响应缓冲的末尾。不再重新分配,因而非常有效。<BR><BR>特别是在将 ADO 记录集转换到 HTML 表时,请考虑使用 GetRows 或 GetString。<BR><BR>如果用 JScript 连接字符串,强烈建议使用 += 操作符;即用 s += "某字符串", 而不是 s = s + "某字符串"。<BR><BR>技巧 21:启用浏览器和代理缓存 <BR><BR>默认情况下,ASP 禁用浏览器和代理中的缓存。这将很有意义,因为 ASP 生来就是动态的,具有潜在地对时间敏感的信息。如果有一个不需要对每次查看进行刷新的页,则应该启用浏览器和代理缓存。这使得浏览器和代理能在某一段时间内,使用某一页的缓存副本,这时间的长短可以控制。缓存能明显减轻服务器负荷,使用户的感受好一些。<BR><BR>哪种动态页可以缓存?举例说明:<BR><BR>天气页,每 5 分钟更新一次。 <BR>列出新闻的主页或新闻发布的主页,每天更新 2 次。 <BR>公共基金运营列表,基本的统计数小时更新 1 次。 <BR>请注意,使用浏览器或代理缓存,只有很少的命中被记录到 Web 服务器上。如果想精确测量所有页面查看或者张贴广告,也许不喜欢使用浏览器和代理缓存。<BR><BR>浏览器缓存是由 Web 服务器发往浏览器的 HTTP 截至期限标题控制的。ASP 提供了两种发送标题的机制。要将页面设置为在未来某个分钟数后过期,请设置 Response.Expires 属性。以下的例子通知浏览器:内容在 10 分钟后过期:<BR><BR>&lt;% Response.Expires = 10 %&gt; <BR><BR>设置 Response.Expires 为负数或 0 则禁用缓存。一定要使用较大的负数,例如 -1000 (大于一天),来克服服务器时钟和浏览器时钟之间的差异。第二个属性 Response.ExpiresAbsolute,允许设置内容过期的指定时间:<BR><BR>&lt;% Response.ExpiresAbsolute = #May 31,2001 13:30:15# %&gt;<BR><BR>如果不想使用 Response 对象设置过期时间,可以将 &lt;META&gt; 标记写入 HTML,通常写在 HTML 文件的 &lt;HEAD&gt; 内部。一些浏览器会响应这条指令,但代理不会。<BR><BR>&lt;META HTTP-EQUIV="Expires" VALUE="May 31,2001 13:30:15"&gt;<BR><BR>最后,可以标识内容对 HTTP 代理缓存是否有效,请使用 Response.CacheControl 属性。设置属性为“Public”,允许代理缓存内容。<BR><BR>&lt;% Response.CacheControl = "ublic" %&gt;<BR><BR>默认情况下,该属性设置为“Private”。注意,不应当为显示某用户专用数据的页启用代理缓存,因为代理也许为属于其他用户的用户页面服务。<BR><BR>技巧 22:尽可能使用 Server.Transfer 替代 Response.Redirect <BR><BR>Response.Redirect 通知浏览器,请求一个不同的页面。该函数经常用于重定向用户到登录或错误页面。既然重定向强制一个新页请求,浏览器就必须做两次到 Web 服务器的往返,而且 Web 服务器必须处理额外的请求。IIS 5.0 引入一个新的函数,Server.Transfer,该函数执行传送到相同服务器上的不同 ASP 页。这样避免了额外的、从浏览器到 Web 服务器的往返,从而改善了整体系统性能,同时改善了对用户的响应时间。请查看重定向中的新方向(英文),它讨论了 Server.Transfer 和 Server.Execute。 <BR><BR>也可以查看Leveraging ASP in IIS 5.0中有关 IIS 5.0 和 ASP 3.0 新功能的完全列表。(英文)<BR><BR>技巧 23:在目录 URL 尾部加斜线 <BR><BR>相关的技巧是,一定要定在指向目录的 URL 尾部加斜线 (/)。如果省略了斜线,浏览器将向服务器提出请求,仅通知它正寻找一个目录。然后浏览器发出第二个请求,在 URL 末尾添加斜线,然后服务器将那个目录的默认文档作为响应,或者如果没有默认文档并且目录浏览已被启用,就以目录列表作为响应。添加了斜线便省去了第一个没用的往返。出于对用户的友好,也许想要在显示的名称的末尾省略斜线。<BR><BR>例如,写:<BR><BR>&lt;a href="http://msdn.microsoft.com/workshop/" title="MSDN Web<BR>Workshop"&gt;http://msdn.microsoft.com/workshop&lt;/a&gt;<BR><BR>它还适用于指向在 Web 站点主页的 URL:请使用下面的: &lt;a href="http://msdn.microsoft.com/"&gt;,不要用 &lt;a href="http://msdn.microsoft.com"&gt;.<BR><BR><BR>技巧 24:避免使用服务器变量 <BR><BR>访问服务器变量将引起 Web 站点向服务器提出特殊的请求,然后收集所有的服务器变量,并不止是需要的那个。这好像从发霉的阁楼中的文件夹中检索某条特殊的信息一样。当想要某条信息时,在访问该信息之前必须先上阁楼取得文件夹。这与请求服务器变量时,性能访问出现第一次请求服务器变量所发生的一样。后续的对其他服务器变量的访问不会引起性能访问。<BR><BR>从不访问不合格的 Request 对象(例如,Request("Data"))。对于不在 Request.Cookies、Request.Form、Request.QueryString 或 Request.ClientCertificate 中的项,有对 Request.ServerVariables 的隐含调用。Request.ServerVariables 集合比其他集合慢很多。<BR><BR>技巧 25:升级为最新的和最好的版本 <BR><BR>系统组件常常升级,建议升级为最新的和最好的版本。最好升级到 Windows 2000(还有,IIS 5.0、ADO 2.5、MSXML 2.5、Internet Explorer 5.0、VBScript 5.1 和 JScript 5.1)。IIS 5.0 和 ADO 2.5 在多处理器计算机上实现了非常好的性能。在 Windows 2000 下,ASP 能良好地扩展到四个处理器或者更多,但是在 IIS 4.0,ASP 不能扩展为超过两个处理器。在应用程序中使用的脚本和 ADO 越多,升级到 Windows 2000 后获得的性能提高就越大。<BR><BR>如果您还无法升级到 Windows 2000 ,可以升级为最新版本的 SQL Server、ADO、VBScript 和 JScript、MSXML、Internet Explorer 和 NT 4 Service Packs。它们都改进了性能并增强了可靠性。<BR><BR>技巧 26:调整 Web 服务器 <BR><BR>有许多 IIS 调节参数可以改进站点性能。例如,使用 IIS 4.0,我们经常发现增加 ASP 的 ProcessorThreadMax 参数(请参阅 IIS 文档)能获得很大的好处,尤其是在经常等待后端资源,例如数据库或其他中间层产品,例如 screen-scrapers,的站点上。在 IIS 5.0 中也许会发现,打开 ASP Thread Gating 比试图为 AspProcessorThreadMax 找一个最佳的设置更为有效。<BR><BR>下面的调整 IIS(英文),是一篇很好的资料。<BR><BR>最佳的配置取决于(在其他因素中)应用程序代码、在其上运行的硬件以及客户端的工作负荷。发现最佳设置的唯一方法是运行性能测试,它将我们带入下一个技巧。<BR><BR>技巧 27:进行性能测试 <BR><BR>如上所述,性能是一种指标。如果您正努力改进站点的性能,请先设置性能目标,然后提高性能直到达到目标为止。请不要将所有的性能测试放在项目的最后。往往到了项目的最后,再做非做不可的体系结构改动已为时太晚,并使客户失望。性能测试是日常测试的一部分。性能测试可以针对独立组件进行,例如 ASP 页面或 COM 对象,也可以将站点作为一个整体进行。<BR><BR>许多人使用单一的浏览器请求页面来测试他们 Web 站点的性能。这将使您对站点的响应有很好的感觉,但对于站点在有负荷下的性能却一无所知。<BR><BR>通常,要准确地测量性能,需要专用的测试环境。这个环境应该由那些,在处理器速度、处理器个数、内存、硬盘、网络配置等方面,能模拟产品硬件的硬件组成。然后,需要定义客户端的工作负荷:有多少并发用户;他们提出请求的频率;他们将访问的页面类型等等。如果您无法从站点获得实际的使用数据,则需要估计它们。最后,需要一个能模拟预期客户端工作负荷的工具。在这些工具的帮助下,可以开始回答一些问题,例如,如果我有 N 个并发用户,需要多少台服务器?您还能找出瓶颈和优化的目标。<BR><BR>下面列出了一些好的 Web 强度测试工具。极力推荐“Microsoft Web 应用程序强度测试 (WAS)”工具包。WAS 允许记录测试脚本,然后模拟成百或上千个访问 Web 服务器的用户。WAS 报告大量统计结果,包括每秒请求数、响应时间的分布和错误计数。WAS 具有增强客户端和基于 Web 的接口;Web 接口允许进行远程测试。<BR><BR>请务必阅读 IIS 5.0 调试指南(英文)。<BR>
回复

使用道具 举报

发表于 2007-9-29 09:35:50 | 显示全部楼层
好长。。。
回复

使用道具 举报

发表于 2009-4-10 09:15:23 | 显示全部楼层

好贴,顶一下楼主!

好贴,顶一下楼主!
















古之立大事者,不惟有超世之才,亦必有坚忍不拔之志。---魔兽剑圣异界纵横
小游戏 极品家丁 龙蛇演义 恶魔法则 飞升之后 异界枪神 凡人修仙传 魔兽领主 超级农民 成人小游戏 极品公子
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 入学

本版积分规则

QQ|Archiver|手机版|小黑屋|校园天空成立于2004年2月24日 ( 陕ICP备08000078号-8 )

GMT+8, 2025-4-29 09:54 , Processed in 0.099548 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表