二十八条改善ASP性能和外观的技巧(二)
在适当的条件下,可以将 ADO 记录集本身缓存在 Application 或 Session 作用域中。有两个警告: 必须将 ADO 标记为自由线程 必须使用断开连接的记录集。 如果不能保证满足这两个要求,则不要缓存 ADO 记录集。在下面的“非敏捷组件”和“不要缓存连接”技巧中,我们将讨论将 COM 对象存储在 Application 或 Session 作用域中的危险性。 当您将数据存储在 Application 或 Session 作用域时,数据将保留在那里,直到您以编程方式改变它、Session 过期或 Web 应用程序重新启动为止。如果数据需要更新怎么办?要手工强制对 Application 数据进行更新,您可以访问只有管理员才可访问的 ASP 页来更新数据。或者,您可以通过函数定期自动刷新数据。下面例子存储带有缓存数据的时间戳,并隔一段时间后刷新数据。’ Function to return the employment status listFunction GetEmploymentStatusListUpdateEmploymentStatusGetEmploymentStatusList = Application(?EmploymentStatusList?)End Function’ Periodically update the cached dataSub UpdateEmploymentStatusListDim d, strLastUpdatestrLastUpdate = 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 Arrayd = FetchEmploymentStatusList()’ Update the Application object. Use Application.Lock()’ to ensure consistent dataApplication.LockApplication(?EmploymentStatusList?) = EventsApplication(?LastUpdate?) = CStr(Now)Application.UnlockEnd IfEnd Sub请参见 World’s Fastest ListBox with Application Data,上面还有一个例子。 要知道在 Session 或 Application 对象中缓存大的数组不是一个好的做法。在访问数组的任何元素之前,脚本语言的语法要求必须临时复制整个数组。例如,如果将由字符串组成的有 100,000 个元素的数组(该数组将美国邮政编码映射到当地的气象站)缓存在 Application 对象中,ASP 必须先将所有的 100,000 个气象站复制到临时数组中,然后才能提取一个字符串。在这种情况下,用自定义方法建立一个自定义组件来存储气象站 - 或使用一个词典组件会更好。 再警告大家一下,不要将婴儿与洗澡水一起倒掉:数组能快速查寻和存储在内存中是邻近的关键数据对。索引一个词典比索引一个数组要慢得多。应针对您的实际情况,选择提供最佳性能的数据结构。 技巧 3:将数据和 HTML 缓存在 Web 服务器的磁盘上有时,数据可能太多,无法都缓存在内存中。“太多”只是一个说法,这要看您想消耗多少内存,以及需缓存的项目数和检索这些项目的频率。在任何情况下,如果数据太多而无法都缓存在内存中,则考虑将数据以文本或 XML 文件缓存在 Web 服务器的硬盘上。可以同时将数据缓存在磁盘和内存中,为您的站点建立最适宜的缓存策略。 注意当测量单个 ASP 页的性能时,检索磁盘上的数据可能不一定要比从数据库检索数据更快。但缓存会降低数据库和网络上的负载。在高负载的情况下,这样做可大大改善总体吞吐量。当缓存开销很大的查询结果(如多表联接或复合存储过程)或大的结果集时,这是非常有效的。与往常一样,要测试一下几种方案的优劣。 ASP 和 COM 提供一些建立基于磁盘的缓存方案的工具。ADO 记录集 Save() 和 Open() 函数保存和装载磁盘中的记录集。可以使用这些方法重新编写上面 Application 数据缓存技巧中的代码示例,用文件的 Save() 代替写到 Application 对象中的代码。 有一些其它组件可以用于文件:
- Scripting.FileSystemObject可使您创建、读和写文件。
- 与 Internet Explorer 一起提供的 Microsoft® XML 解析器 (MSXML) 支持保存和装载 XML 文档。
- LookupTable 对象(例如,用在 MSN 上)是从磁盘装载简单列表的最好选择。
- 自由线程的组件(除非它们聚集 FTM)。
- 单元线程组件。
- 单线程组件。
- COM 对象有利于将表示逻辑与业务逻辑分开。
- COM 对象可以保证代码重复使用。
- 许多开发人员发现以 VB、C++ 或 Visual J++ 编写的代码比 ASP 更容易调试。
- 低级隔离。这在 IIS 的所有版本中都得到支持,且是最快的。它在 Inetinfo.exe 中运行 ASP,Inetinfo.exe 是主要 IIS 进程。如果 ASP 应用程序崩溃,IIS 也会崩溃。(要在 IIS 4.0 下重新启动 IIS,Web 站点管理员应使用诸如 InetMon 之类的工具监视站点,如果服务器发生故障,应启用批处理文件以重新启动服务器。IIS 5.0 引入了可靠的重新启动,该方法可使发生故障的服务器自动重新启动。)
- 中级隔离。IIS 5.0 引入了这个新的级别,它被称为进程外级别,因为 ASP 在 IIS 进程之外运行。在中级隔离中,被配置作为中级隔离运行的所有 ASP 应用程序都共享一个进程空间。这就减少了在一台服务器运行多个进程外 ASP 应用程序所需要的进程数量。中级隔离是 IIS 5.0 中的默认隔离级别。
- 高级隔离。在 IIS 4.0 和 IIS 5.0 中支持这一级别,高级隔离也是进程外的。如果 ASP 崩溃,Web 服务器并不会崩溃。下次 ASP 请求时,ASP 应用程序就会自动重新启动。在高级隔离中,配置作为高级隔离运行的每个 ASP 应用程序都在其自有进程空间中运行。这样做可保护 ASP 应用程序彼此之间不相互干扰。其缺点是它要求每个 ASP 应用程序都要有一个单独的进程。当在一台服务器上必须运行许多应用程序时,系统开销就会大大增加。
- 在 IIS 4.0 中,使用 ASP 低隔离级别,使用 MTS 服务器程序包。
- 在 IIS 5.0 上,使用 ASP 的中隔离级,并使用 COM+ 库应用程序。技巧 10:使用显式选项 在 .asp 文件中应使用 Option Explicit。此指令放在 .asp 文件的最上面,它强制开发人员声明要使用到的所有变量。许多程序员认为这种方法对于调试应用程序很有帮助,因为这种方法避免了键错变量名和误建新变量的可能性(例如,将 MyXMLString=) 错写成 MyXLMString=...。 更重要的一点也许是,声明的变量比未声明的变量速度更快。由此,脚本在运行时每次用到未声明的变量时,按名称引用它。另一方面,声明的变量是有顺序的,要么以编译时间,要么以运行时间。以后,声明的变量都按此顺序引用。因为 Option Explicit 强制变量声明,它能确保声明所有变量,因此访问的速度也很快。 技巧 11:在子例程和函数中使用局部变量 局部变量是那些在子例程和函数内声明的变量。在函数或子例程内,局部变量访问比全局变量访问更快。局部变量的使用也会使代码更清晰,因此应尽量使用局部变量。 技巧 12:将经常使用的数据复制到脚本变量中 当访问 ASP 中的 COM 对象时,应将经常使用的对象数据复制到脚本变量中。这样做可减少 COM 方法调用,因为 COM 方法调用与访问脚本变量相比,开销相对较大。当访问 Collection 和 Dictionary 对象时,这种技术也会减少开销很大的查找。 一般来说,如果您打算不止一次访问对象数据,那么就应将数据放到脚本变量中。这种优化的主要目标是 Request 变量(Form 和 QueryString 变量)。例如,您的站点可传递一个名为 UserID 的 QueryString 变量。假设此 UserID 在特定页面上被引用 12 次。可以无须调用 Request(?UserID?) 12 次,而是在 ASP 页面最上面将 UserID 指派到一个变量。然后在该页面自始至终使用该变量。这样就省去了 11 次 COM 方法调用。 实际上,访问 COM 属性或方法的开销并没有那么大。下面举一个例子,说明某相当常见的代码(从语法上讲): Foo.bar.blah.baz = Foo.bar.blah.qaz(1)If Foo.bar.blah.zaq = Foo.bar.blah.abc Then ’ ...