ASP中处理#include

在ASP中处理#include 文件与用编译高级编程语言，如C/C++处理包含文件，这两种方法之间有两个主要区别。
第一，ASP不从最终形成的ASP文件中移走那些未涉及到的信息。这是因为ASP独立于脚本引擎，不过多地进行代码
分析。大体说来，如果遇到了ASP文件的基本语法请求，信息就被缓存（假定缓冲器是打开的）并被发送到适当
的脚本引擎，进行进一步的分解、标记及执行。
除了这个“死码”问题，ASP包含文件与编译语言之间的另一个区别在于：每个ASP文件都可以被看作它自己
的程序。只要一个页面不包含另一个，在ASP的意义上看来它们就没有关系，尽管二者对整个站点的运行都很
关键。因此，被两个不同页面所共享的一个#include 文件必须要被两个文件都完全包含。从本质上说，ASP不具
备许多高级语言所具备的连接器的优势，连接器可以用来避免包含文件中代码和数据的冗余。
如果把我所概括的ASP包含文件的问题组合起来，结论就是：它对一个大型站点的内存将是破坏性的。想象
一下这种情况：一个包含文件中包含了可能要用到的所有共享程序。按照这种设计，导致的结果是所有的ASP页
都必须包含这一关键的文件。如果EverythingButTheKitchenSink.inc 经过分解之后与ASP文件的平均长度相同，
那么被ASP分配并为缓存的ASP文件使用的内存中的一半都充满了本来多余没用的信息。
813
调用NT Task Manager/Processes 可以看到正被站点所使用着的内存，并观察一下多少内存是由mtx.exe
（如果站点被设置成独立的程序在IIS4上运行），dllhost.exe （如果站点被设置成独立的程序在IIS5上运行），
或是inetinfo.exe （如果不是独立的，见下面的图）这些程序所使用。想要掌握内存增加得有多快，一个很好的
测试方法是启动IIS后调用一个简单的页面来看看内存的大小。（看内存之前要调用一个ASP文件，因为在处理第
一个ASP文件时要建立一些普通的通用文件）。现在在你的站点上使用其它ASP文件，并监控每一个被使用的ASP文
件对内存的作用。
比如说我创建了ASP文件。第一个文件RunFirst.asp，是一个小文件，在观察内存之前初始化ASP资源。另外
两个文件除了它们所要使用的#include 文件信息不同以外，是完全一样的。将这些文件复制到你的wwwroot目录下，
然后按顺序运行RunFirst.asp, HelloWorld1.asp和 HelloWorld2.asp，执行HelloWorld1.asp和HelloWorld2.asp
之后观察内存，你会发现后者使用了更多的内存。这是因为它使用的#include 文件中有一个很大的未使用的程序，
BigAndUnreferenced, 它对页面的运行结果没有任何作用，但却占据了400K的内存。在Windows 2000 Server
w/ IIS5 上依次进行下列步骤得到的结果是：
运行RunFirst.asp 后内存6,104K
运行HelloWorld1.asp后内存 6,124K
运行HelloWorld2.asp后内存 6,544K
仅仅按照这个顺序没有什么明显的意义，颠倒装载顺序之后的结果是：
运行 RunFirst.asp 后内存6,096K
运行 HelloWorld2.asp后内存 6,536K
运行 HelloWorld1.asp 后内存6,540K
请注意开始和结束的内存数不完全一致，因为内存管理器根据最近的请求大块地分配内存。但是相对而言，
最终的轮廓总是HelloWorld2.asp 占据大块的内存份额。本文结尾处可以下载这些简短的代码。浏览以下这些
代码，但要分清内存的不同：
RunFirst.asp 是这样的：
< %@ LANGUAGE="VBSCRIPT" % >
< HTML >
< HEAD >< TITLE >Seed Page to load general ASP resources< /TITLE >< HEAD >
< BODY >
< %
Response.Write "Seed Page Loaded"
% >
< /BODY >
< /HTML >
HelloWorld1.asp 是这样的：
< %@ LANGUAGE="VBSCRIPT" % >
< !--#include virtual ="/HelloWorld1.inc"-- >
< HTML >
< HEAD >< TITLE >Hello World using little memory< /TITLE >< HEAD >
< BODY >
< %
SayHello
% >
< /BODY >
< /HTML >
HelloWorld1.inc代码是:
< %
Sub SayHello
Response.Write "Hello World 1"
End Sub
% >
HelloWorld2.asp代码是：
< %@ LANGUAGE="VBSCRIPT" % >
< !--#include virtual ="/HelloWorld2.inc"-- >
< HTML >
< HEAD >< TITLE >Hello World using a lot of memory< /TITLE >< HEAD >
< BODY >
< %
SayHello
% >
< /BODY >
< /HTML >
但是HelloWorld2.inc要大一些:
< %
Sub SayHello
Response.Write "Hello World 2"
End Sub
Sub BigAndUnreferenced
' This does a lot of redundant stuff to increase memory
Dim textVar
textVar = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
' this line is duplicated 1,000 times
End Sub
% >
本文中对内存资源的讨论是以缓冲器打开为前提的。如果缓冲器没有打开，那么每个ASP文件集中装载页面
的所有组成部分，页面执行之后再释放这些内容。多数站点都在一定程度上打开缓冲器，因为大量点击的站点
的运行请求这样的要求。即使由于某种原因不打开缓冲器，仍可能受到#include 文件问题的影响，表现为内存波动较
大和处理速度慢。
这里有一些技巧供你参考使用，如：
重新构造包含文件
重新构造包含文件可能是目前你所能做的最容易的事。列出所有包含文件，查找问题的以下迹象：
○ #include 文件是否包含着多种函数？内存效率最高的包含文件应该是特定函数的，以减少死码的可能性。
例如一个处理日期和时间的包含文件，可以把它分成两个文件，各处理一个方面：一个单独的ASP只需要处理一种
类型。
○ #include 文件是否专门存储整个应用程序所公用的常量？这类文件，根据其大小，可以导致问题发生，
因为通常它们需要被包含在所有的其它包含文件中，就造成了包含文件嵌套。可以将常量放置在它们所引用的
包含文件中。如果常量是ASP文件内部需要的，就可以创建与它们的使用种类有关的较小的常量文件。
○ #include 文件中是否包含作废的函数？有些函数/程序是站点过去使用过的，已经过了使用期限还挂在那里。
如果在不可预见的未来某一时间，有可能再次使用它们，就应该创建一个小心存档的文档文件，说明该函数/程序从
哪里来，何时被移走的，而不是将他们留在活动文件中。版本控制系统对清除旧资源也有所帮助，因为它很容易
被覆盖。
○ 你对第三方包含文件了解充分吗？因为涉及到内存问题，你应该明白你的包含文件有多大（甚至于那些你
没有直接创建的）并且判定一下是否真的需要它们。
你也许会想，这些削减和修改是否在实际上增加了包含文件的数量，在ASP文件中需要更多的#include声明？
在大多数情况下，答案是肯定的。这是更好地使用包含文件的代价，但是一旦完成了最初的转换，就不会增加管
理ASP文件的难度。
将代码放入对象中
也许你正在经历由#include 而引起的内存膨胀，好在可以在站点中用对象多做一些工作。如果你坚持在
脚本中执行函数，可以考虑使用Scriptlet 。在ASPToday站点和其它刊物上有许多文章讨论这些技巧。Scriptlet
可以很好地减少所使用的包含文件的数量：大部分代码写完后，从包含函数到它在对象中的封装之间的过渡
相当容易。只需要围绕现有代码的几句额外的语法和调用方法的一些改变，就完成了对象。另一个优势在于
scriptlet对象本身就可以被共享，从而进一步减少内存需求。
如果你想要更大的改变，可以考虑可以移植到更快的编译语言，如like VB, VC++/ATL, 或 Delphi 上的
函数。这样一来你的应用程序速度真的得到了提高，因为这时所执行的是最优化的代码而不是解释脚本。这种
转变的复杂性显然依所选语言而不同。比如说，从VBScript 到 VB 就非常直接，而从VBScript 到 VC++/ATL
就复杂多了。可以先作成scriptlet，然后取几个这样的新对象并将它们移到编译语言中去。最好的选择要么
是很大的对象，它可以节省内存，要么就是使用最频繁的对象，它可以相当地提高性能。
不管你使用什么语言，使用对象都可以帮助IIS优化管理机器资源，因为这时是在MTS 下运行，并利用它的
所有优势：连接pooling、对象共享及其它。
利用Server.Execute 和 Server.Transfer (仅限于ASP3/IIS5)
有一个好消息是Microsoft已经认识到了这些问题，正在用IIS5带的ASP3提供解决这些问题的新技术。有
两种新的服务器方法可以把你从过多的包含文件中解脱出来。它们使用同一个自变量：ASP文件名。Server.Execute
调用所提供的ASP文件，执行并返回调用者。Server.Transfer 将控制转换到提供的ASP文件，但不返回。两个
调用运行文件的方式就好象它们在调用者ASP应用程序内。最后这一点很重要，因为现有的文件规定可以从其它
应用程序中调用ASP文件。
这些调用的思路是将公用的程序放入ASP文件中，然后在其它ASP文件中需要的地方直接执行它们。这类似于
动态的#include ，在调用页中不使用额外内存。他们非常有效，因为执行的独立的ASP文件，拥有被缓存和被
共享的一切有利条件。而对包含文件中的公用程序而言，每个使用它们的ASP文件都要装载并要保留一份拷贝。
Server.Execute 的一个很好的特点是运行条件包含的能力。通常情况下包含不能是有条件的，因为#include
指示是在脚本代码执行处理条件之前预先处理的。但是用Server.Execute 可以写出这样的代码，查看一个
session变量，决定调用哪一部分代码，而不是总是装载着两部分代码。
If Session("DoThisOrThat") = "this" Then
Server.Execute("this.asp")
Else
Server.Execute("that.asp")
End If
如果IIS5发行后很快你就能使用（甚至于在此之前，如果你敢在你的站点上使用试用版的话），那么你就
不用为削减你的包含文件而太担心，相反应该把时间花在模块化成可直接调用的ASP文件上，或者象上面所说
的将代码移入对象中。
总结
包含文件的核心思想是：它们是共享代码的最简单方式之一，并且能简化模式站点的设计。我曾经使用过的所
有的先进编程语言都有共享源文件的方法，ASP脚本模型也不例外。一个通用的规则是，倾向于使用包含文件而不是克
隆代码，但是考虑到ASP在IIS下处理内存空间的独特方式，注意到这个问题是值得的。
注意在此提到的在站点缩小占用内存的方法。用Task Manager 或类似的工具来观察mtx.exe (IIS4),
dllhost.exe (IIS5)或 inetinfo,exe (IIS4/5) 的内存大小。你会因一个效率更高的运行站点受益，你的
系统管理员也会因为节省出来的内存芯片而高兴。