ASP.NET网站的性能优化【二】
8. 将 SqlDataReader 类用于快速只进数据游标
SqlDataReader 类提供了一种读取从 SQL Server 数据库检索的只进数据流的方法。如果当创建 ASP.NET 应用程序时出现允许您使用它的情况,则 SqlDataReader 类提供比 DataSet 类更高的性能。情况之所以这样,是因为 SqlDataReader 使用 SQL Server 的本机网络数据传输格式从数据库连接直接读取数据。另外,SqlDataReader 类实现 IEnumerable 接口,该接口也允许您将数据绑定到服务器控件。有关更多信息,请参见 SqlDataReader 类。有关 ASP.NET 如何访问数据的信息,请参见通过 ASP.NET 访问数据。
9. 将 SQL Server 存储过程用于数据访问
在 .NET Framework 提供的所有数据访问方法中,基于 SQL Server 的数据访问是生成高性能、可缩放 Web 应用程序的推荐选择。使用托管 SQL Server 提供程序时,可通过使用编译的存储过程而不是特殊查询获得额外的性能提高。
10. 避免单线程单元 (STA) COM 组件
默认情况下,ASP.NET 不允许任何 STA COM 组件在页面内运行。若要运行它们,必须在 .aspx 文件内将 ASPCompat=true 属性包含在 @ Page 指令中。这样就将执行用的线程池切换到 STA 线程池,而且使 HttpContext 和其他内置对象可用于 COM 对象。前者也是一种性能优化,因为它避免了将多线程单元 (MTA) 封送到 STA 线程的任何调用。
使用 STA COM 组件可能大大损害性能,应尽量避免。若必须使用 STA COM 组件,如在任何 interop 方案中,则应在执行期间进行大量调用并在每次调用期间发送尽可能多的信息。另外,小心不要在构造页面期间创建任何 STA COM 组件。例如下面的代码中,在页面构造时将实例化由某个线程创建的 MySTAComponent,而该线程并不是将运行页面的 STA 线程。这可能对性能有不利影响,因为要构造页面就必须完成 MTA 和 STA 线程之间的封送处理。
首选机制是推迟对象的创建,直到以后在 STA 线程下执行.
推荐的做法是在需要时或者在 Page_Load 方法中构造任何 COM 组件和外部资源。
永远不要将任何 STA COM 组件存储在可以由构造它的线程以外的其他线程访问的共享资源里。这类资源包括像缓存和会话状态这样的资源。即使 STA 线程调用 STA COM 组件,也只有构造此 STA COM 组件的线程能够实际为该调用服务,而这要求封送处理对创建者线程的调用。此封送处理可能产生重大的性能损失和可伸缩性问题。在这种情况下,请研究一下使 COM 组件成为 MTA COM 组件的可能性,或者更好的办法是迁移代码以使对象成为托管对象。
11. 将调用密集型的 COM 组件迁移到托管代码
.NET Framework 提供了一个简单的方法与传统的 COM 组件进行交互。其优点是可以在保留现有投资的同时利用新的平台。但是在某些情况下,保留旧组件的性能开销使得将组件迁移到托管代码是值得的。每一情况都是不一样的,决定是否需要迁移组件的最好方法是对 Web 站点运行性能测量。建议您研究一下如何将需要大量调用以进行交互的任何 COM 组件迁移到托管代码。
许多情况下不可能将旧式组件迁移到托管代码,特别是在最初迁移 Web 应用程序时。在这种情况下,最大的性能障碍之一是将数据从非托管环境封送到托管环境。因此,在交互操作中,请在任何一端执行尽可能多的任务,然后进行一个大调用而不是一系列小调用。例如,公共语言运行库中的所有字符串都是 Unicode 的,所以应在调用托管代码之前将组件中的所有字符串转换成 Unicode 格式。
另外,一处理完任何 COM 对象或本机资源就释放它们。这样,其他请求就能够使用它们,并且最大限度地减少了因稍后请求垃圾回收器释放它们所引起的性能问题。
12. 在 Visual Basic .NET 或 JScript 代码中使用早期绑定
以往,开发人员喜欢使用 Visual Basic、VBScript 和 JScript 的原因之一就是它们所谓“无类型”的性质。变量不需要显式类型声明,并能够简单地通过使用来创建它们。当从一个类型到另一个类型进行分配时,转换将自动执行。不过,这种便利会大大损害应用程序的性能。
Visual Basic 现在通过使用 Option Strict 编译器指令来支持类型安全编程。为了向后兼容,默认情况下,ASP.NET 不启用该选项。但是,为了得到最佳性能,强烈建议在页中启用该选项。若要启用 Option Strict,请将 Strict 属性包括在 @ Page 指令中,或者,对于用户控件,请将该属性包括在 @ Control 指令中。下面的示例演示了如何设置该属性,并进行了四个变量调用以显示使用该属性是如何导致编译器错误的。
JScript .NET 也支持无类型编程,但它不提供强制早期绑定的编译器指令。若发生下面任何一种情况,则变量是晚期绑定的:
被显式声明为 Object。
是无类型声明的类的字段。
是无显式类型声明的专用函数或方法成员,并且无法从其使用推断出类型。
最后一个差别比较复杂,因为如果 JScript .NET 编译器可以根据变量的使用情况推断出类型,它就会进行优化。在下面的示例中,变量 A 是早期绑定的,但变量 B 是晚期绑定的。
以下是引用片段:
var A;
var B;
A = "Hello";
B = "World";
B = 0;
为了获得最佳的性能,当声明 JScript .NET 变量时,请为其分配一个类型。例如,var A : String。
【待续...】
SqlDataReader 类提供了一种读取从 SQL Server 数据库检索的只进数据流的方法。如果当创建 ASP.NET 应用程序时出现允许您使用它的情况,则 SqlDataReader 类提供比 DataSet 类更高的性能。情况之所以这样,是因为 SqlDataReader 使用 SQL Server 的本机网络数据传输格式从数据库连接直接读取数据。另外,SqlDataReader 类实现 IEnumerable 接口,该接口也允许您将数据绑定到服务器控件。有关更多信息,请参见 SqlDataReader 类。有关 ASP.NET 如何访问数据的信息,请参见通过 ASP.NET 访问数据。
9. 将 SQL Server 存储过程用于数据访问
在 .NET Framework 提供的所有数据访问方法中,基于 SQL Server 的数据访问是生成高性能、可缩放 Web 应用程序的推荐选择。使用托管 SQL Server 提供程序时,可通过使用编译的存储过程而不是特殊查询获得额外的性能提高。
10. 避免单线程单元 (STA) COM 组件
默认情况下,ASP.NET 不允许任何 STA COM 组件在页面内运行。若要运行它们,必须在 .aspx 文件内将 ASPCompat=true 属性包含在 @ Page 指令中。这样就将执行用的线程池切换到 STA 线程池,而且使 HttpContext 和其他内置对象可用于 COM 对象。前者也是一种性能优化,因为它避免了将多线程单元 (MTA) 封送到 STA 线程的任何调用。
使用 STA COM 组件可能大大损害性能,应尽量避免。若必须使用 STA COM 组件,如在任何 interop 方案中,则应在执行期间进行大量调用并在每次调用期间发送尽可能多的信息。另外,小心不要在构造页面期间创建任何 STA COM 组件。例如下面的代码中,在页面构造时将实例化由某个线程创建的 MySTAComponent,而该线程并不是将运行页面的 STA 线程。这可能对性能有不利影响,因为要构造页面就必须完成 MTA 和 STA 线程之间的封送处理。
首选机制是推迟对象的创建,直到以后在 STA 线程下执行.
推荐的做法是在需要时或者在 Page_Load 方法中构造任何 COM 组件和外部资源。
永远不要将任何 STA COM 组件存储在可以由构造它的线程以外的其他线程访问的共享资源里。这类资源包括像缓存和会话状态这样的资源。即使 STA 线程调用 STA COM 组件,也只有构造此 STA COM 组件的线程能够实际为该调用服务,而这要求封送处理对创建者线程的调用。此封送处理可能产生重大的性能损失和可伸缩性问题。在这种情况下,请研究一下使 COM 组件成为 MTA COM 组件的可能性,或者更好的办法是迁移代码以使对象成为托管对象。
11. 将调用密集型的 COM 组件迁移到托管代码
.NET Framework 提供了一个简单的方法与传统的 COM 组件进行交互。其优点是可以在保留现有投资的同时利用新的平台。但是在某些情况下,保留旧组件的性能开销使得将组件迁移到托管代码是值得的。每一情况都是不一样的,决定是否需要迁移组件的最好方法是对 Web 站点运行性能测量。建议您研究一下如何将需要大量调用以进行交互的任何 COM 组件迁移到托管代码。
许多情况下不可能将旧式组件迁移到托管代码,特别是在最初迁移 Web 应用程序时。在这种情况下,最大的性能障碍之一是将数据从非托管环境封送到托管环境。因此,在交互操作中,请在任何一端执行尽可能多的任务,然后进行一个大调用而不是一系列小调用。例如,公共语言运行库中的所有字符串都是 Unicode 的,所以应在调用托管代码之前将组件中的所有字符串转换成 Unicode 格式。
另外,一处理完任何 COM 对象或本机资源就释放它们。这样,其他请求就能够使用它们,并且最大限度地减少了因稍后请求垃圾回收器释放它们所引起的性能问题。
12. 在 Visual Basic .NET 或 JScript 代码中使用早期绑定
以往,开发人员喜欢使用 Visual Basic、VBScript 和 JScript 的原因之一就是它们所谓“无类型”的性质。变量不需要显式类型声明,并能够简单地通过使用来创建它们。当从一个类型到另一个类型进行分配时,转换将自动执行。不过,这种便利会大大损害应用程序的性能。
Visual Basic 现在通过使用 Option Strict 编译器指令来支持类型安全编程。为了向后兼容,默认情况下,ASP.NET 不启用该选项。但是,为了得到最佳性能,强烈建议在页中启用该选项。若要启用 Option Strict,请将 Strict 属性包括在 @ Page 指令中,或者,对于用户控件,请将该属性包括在 @ Control 指令中。下面的示例演示了如何设置该属性,并进行了四个变量调用以显示使用该属性是如何导致编译器错误的。
JScript .NET 也支持无类型编程,但它不提供强制早期绑定的编译器指令。若发生下面任何一种情况,则变量是晚期绑定的:
被显式声明为 Object。
是无类型声明的类的字段。
是无显式类型声明的专用函数或方法成员,并且无法从其使用推断出类型。
最后一个差别比较复杂,因为如果 JScript .NET 编译器可以根据变量的使用情况推断出类型,它就会进行优化。在下面的示例中,变量 A 是早期绑定的,但变量 B 是晚期绑定的。
以下是引用片段:
var A;
var B;
A = "Hello";
B = "World";
B = 0;
为了获得最佳的性能,当声明 JScript .NET 变量时,请为其分配一个类型。例如,var A : String。
【待续...】