Coin163

首页 > 提高ASP.NET 应用程序的性能

提高ASP.NET 应用程序的性能

2020腾讯云双十一活动,全年最低!!!(领取3500元代金券),
地址https://cloud.tencent.com/act/cps/redirect?redirect=1074

【阿里云】双十一活动,全年抄底价,限时3天!(老用户也有),
入口地址https://www.aliyun.com/1111/home

相关推荐:ASP.NET网站发布问题:服务器应用程序不可用

最近发布一个ASP.NET网站,出现问题“服务器应用程序不可用”。查看了系统事件日志发现,问题的具体原因是:未能初始化 AppDomain:/LM/W3SVC/241265814/Root Exception: System.IO.FileLoadException Message: 未能加载文件或程序集“System.Web, Version=2.0.

这些内容来自微软MSDN,首先我简单整理了一下,第二,加入了一些自己的看法,如果有不对的地方,还请大家一起讨论:

页面和服务器控件处理

避免到服务器的不必要的往返行程   在某些情况下不必使用 ASP.NET 服务器控件和回发事件处理。个人认为:除非必要,尽量避免。如果处理的事务没有需要特别保密的情况,尽量放在客户端完成。例如,在 ASP.NET 网页中验证用户输入经常可在数据提交到服务器之前在客户端进行。

 

使用 Page 对象的 IsPostBack 属性来避免对往返行程执行不必要的处理   如果您编写处理服务器控件回发处理的代码,有时可能需要代码仅在首次请求页时执行,而不是每次回发时都执行。根据该页是否是响应服务器控件事件生成的,使用 IsPostBack 属性有条件地执行代码。事实上,很多内容仅仅需要访问者第一次登陆才需要查看,其他情况下,并不需要显示。这也有效遏制了资源的浪费。对于此,我们应该谨慎。毕竟,你的站点并非仅仅运行在局域网中。

只在必要时保存服务器控件视图状态   自动视图状态管理使服务器控件可以在往返行程中重新填充它们的属性值,而您不需要编写任何代码。但是,因为服务器控件的视图状态在隐藏的窗体字段中往返于服务器,所以该功能会对性能产生影响。您应该了解在哪些情况下视图状态会有所帮助,在哪些情况下它影响页的性能。例如,如果您将服务器控件绑定到每个往返行程上的数据,因为控件的值会在数据绑定期间用新值替换,所以保存的视图状态没有用处。在这种情况下,禁用视图状态可以节省处理时间并减少页的大小。|
默认情况下,为所有服务器控件启用视图状态。若要禁用它,请将控件的 EnableViewState 属性设置为 false,如下面的 DataGrid 服务器控件示例所示:

 
<asp:datagrid EnableViewState="false" datasource="..." 
   runat="server"/>

您还可以使用 @ Page 指令禁用整个页的视图状态。当您不从页回发到服务器时,这将十分有用:

 
<%@ Page EnableViewState="false" %>
Note注意

@ Control 指令中还支持 EnableViewState 属性以指定是否为用户控件启用视图状态。

这里,我们可以做一个列表,就需要的控件或者页进行分类,划分哪些是必须得使用视图状态的,哪些是肯定不能用的,最后就是可用可不用的了。如果可能,最好划分的结果仅仅在必须使用的情况下使用。

除非有特殊的原因要关闭缓冲,否则使其保持打开状态   禁用 ASP.NET 网页的缓冲会导致大量的性能开销。这里大部分工作人员都不会刻意去关闭缓冲。顺便说一句,Buffer 已被否决,而代之以 BufferOutput,提供了只是为了与以前的 ASP 版本兼容。在 ASP.NET 中,我们使用的是BufferOutput。

使用 Transfer Server 对象或跨页发送的方法在同一个应用程序中的不同 ASP.NET 页之间重定向 如果我们希望网页之间实现链接,可以使用<a> 来创建静态链接,也可以通过使用 HyperLink 控件实现。在此情况下,目标页使用 HTTP GET 命令进行调用。因此,不会将与源页有关的任何信息传递到目标页,除非在目标页的 URL 上指定查询字符串。如果源页和目标页位于同一 Web 应用程序中,它们可以使用会话状态或应用程序状态来共享信息。
跨页发送与超链接的类似之处在于通过用户操作来启动传输。但是,在跨页发送中,目标页是使用 HTTP POST 命令调用的,该命令会将源页上控件的值发送到目标页。此外,如果源页和目标页位于同一 Web 应用程序中,则目标页可以访问源页的公共属性。应用程序中的所有页始终可以共享会话状态或应用程序状态中存储的信息。

状态管理

当不使用会话状态时禁用它   并不是所有的应用程序或页都需要具体用户的会话状态;在不需要时应该禁用会话状态。若要禁用页的会话状态,请将 @ Page 指令中的 EnableSessionState 属性设置为 false。如果页需要访问会话变量,但不打算创建或修改它们,则将 @ Page 指令中的 EnableSessionState 属性设置为 ReadOnly。还可以禁用 XML Web services 方法的会话状态。若要禁用应用程序的会话状态,请在应用程序的 Web.config 文件的 SessionState 节中将 Mode 属性设置为 Off。老样子,除了必须提供用户会话状态的时刻,我们都不需要开启此状态。

针对应用程序需要,选择适当的会话状态提供程序   ASP.NET 为存储应用程序的会话数据提供了三种方法:进程内会话状态、作为 Windows 服务的进程外会话状态和 SQL Server 数据库中的进程外会话状态。当然,还可以创建自定义会话状态提供程序,以在所选数据存储区中存储会话数据。面对这些方法的时候如何选择是个问题。毫无疑问,每种方法都有自己的优点,如果你能清楚的知道在什么时候使用什么样的会话,当然是好的。如果不清楚,那么就选择进程内会话状态。这是迄今为止速度最快的解决方案。

数据访问

将 SQL Server 和存储过程用于数据访问   在 .NET Framework 提供的所有数据访问方法中,使用 SQL Server 进行数据访问是生成高性能、可缩放 Web 应用程序的推荐选择。这种方案需要SQL Server,我们在工作中,可以选择SQL Server的客户端文件。这或许是一种比较两全其美的方法。当然,大家最好SQL Server中的各种操作。比如创建存储过程。

将 SqlDataReader 类用于快速只进数据游标   SqlDataReader 类提供了从 SQL Server 数据库检索的只进数据流。如果您可以在 ASP.NET 应用程序中使用只读流,则 SqlDataReader 类提供比 DataSet 类更高的性能。SqlDataReader 类使用 SQL Server 的本机网络数据传输格式从数据库连接直接读取数据。当绑定到从 SQL Server 返回数据的数据源控件时,通过返回 SqlDataReader 对象,您在只读方案下可以获得更好的性能。例如,当绑定到 SqlDataSource 控件时,通过将 DataSourceMode 属性设置为 DataReader,您将获得更好的性能。(使用数据读取器会导致某些功能的丢失。)另外,SqlDataReader 类实现 IEnumerable 接口,该接口也使您可以将数据绑定到服务器控件。有关更多信息,请参见 SqlDataReader 类。有关 ASP.NET 如何访问数据的信息,请参见通过 ASP.NET 访问数据。

尽可能缓存数据和页输出   ASP.NET 提供了一些机制,它们会在不需要为每个页请求动态计算页输出或数据时缓存这些页输出或数据。另外,通过设计要进行缓存的页和数据请求(特别是在站点中预期将有较大通讯量的区域),可以优化这些页的性能。与使用 .NET Framework 的任何其他功能相比,适当地使用缓存可以更好地提高站点的性能。

使用 ASP.NET 缓存有两点需要注意。首先,不要缓存太多项。缓存每个项均有开销,主要是在内存使用方面。不要缓存容易重新计算和很少使用的项。其次,给缓存项分配的有效期不要太短。很快到期的项会导致缓存中不必要的周转,并且会导致额外的代码清除和垃圾回收工作。使用与“ASP.NET Applications”性能对象关联的“Cache Total Turnover Rate”(缓存总流通率)性能计数器,您可以监视缓存中由于项到期而导致的周转。高周转率可能说明存在问题,特别是当项在到期前被移除时。(这种情况有时称作内存压力。)

Web 应用程序

如果有大型 Web 应用程序,请预编译它   在第一次对应用程序资源(如页)的请求中,Web 应用程序是批编译的。如果应用程序中的页面没有被分析并编译,批编译功能会成批分析并编译目录中的所有页面,以便更好地利用磁盘和内存。此功能带给 ASP.NET 性能上的好处,因为它将许多页面编译为单个程序集。从已加载的程序集访问一页比每页加载新的程序集要快。请注意,如果将多个页面批编译到一个目录超出 BatchTimeout 属性指定的秒数,则将分析并编译单个页面,以便请求能被快速处理。

批编译的缺点在于:如果服务器接收到许多对尚未编译的页面的请求,那么当 Web 服务器分析并编译它们时,性能可能较差。要解决此问题,可以预编译应用程序。有关详细信息,请参见 ASP.NET 网站预编译。

在 Internet 信息服务 5.0 上运行 ASP.NET Web 应用程序时回收进程   默认情况下,IIS 5.0 上的 ASP.NET 将使用进程外的辅助进程为请求提供服务。此功能已被优化以提高吞吐量。由于在进程外的辅助进程中运行 ASP.NET 有其功能和优点,建议在生产站点上使用它。

为了保证稳定性和性能,应定期回收进程。经过较长的时间,有内存泄漏和 bug 的资源可以影响 Web 服务器的吞吐量,而回收进程可以清理内存避免这类问题。但是,应当平衡定期回收的需求和过频的回收,因为停止辅助进程、重新加载页面并重新获取资源和数据的开销可能会超过回收的好处。

相关推荐:使用Chrome DevTools的Timeline和Profiles提高Web应用程序的性能

http://www.oschina.net/translate/performance-optimisation-with-timeline-profiles

在使用 IIS 6.0 的 Windows Server 2003 上运行的 ASP.NET Web 应用程序不需要调整进程模型设置,因为 ASP.NET 将使用 IIS 6.0 进程模型设置。

必要时调整应用程序每个辅助进程的线程数   ASP.NET 的请求结构试图在执行请求的线程数和可用资源之间达到一种平衡。该结构将根据可用于请求的 CPU 功率,来决定允许同时执行的请求数。这项技术称作线程门控。但是在某些条件下,线程门控算法不是很有效。通过使用与“ASP.NET Applications”性能对象关联的“Pipeline Instance Count”(管线实例计数)性能计数器,可以在 Windows 性能监视器中监视线程门控。

当 ASP.NET 网页调用外部资源,如执行数据库访问或 XML Web services 请求时,页面请求通常停止并释放 CPU 以处理其他线程,直到外部资源响应为止。如果另一个请求正在等待处理,并且线程池中有一个线程释放,则开始处理这个正在等待的请求。这可能导致 ASP.NET 辅助进程或应用程序池中存在大量同时执行的请求和许多正在等待的线程,而它们会影响 Web 服务器的吞吐量,从而对性能产生不利的影响。

为缓和这种情况,可以通过更改 Machine.config 配置文件 processModel 元素(ASP.NET 设置架构)节中的 MaxWorkerThreads 和 MaxIOThreads 属性,手动设置进程中的线程数限制。
辅助线程是用来处理 ASP.NET 请求的,而 IO 线程则是用于为来自文件、数据库或 XML Web services 的数据提供服务的。
 

分配给进程模型属性的值是进程中每个 CPU 每类线程的最大数目。对于双处理器计算机,最大数是设置值的两倍。对于四处理器计算机,最大值是设置值的四倍。对于有一个或两个处理器的计算机,默认值就可以,但对于有两个以上处理器的计算机的性能,进程中有一百或两百个线程则弊大于利。因为额外的上下文交换导致操作系统将 CPU 周期花在维护线程而不是处理请求上,所以进程中有太多线程往往会降低服务器的速度。线程适当的数目最好通过应用程序的性能测试来确定。

对于广泛依赖外部资源的应用程序,请考虑在多处理器计算机上启用网络园艺   ASP.NET 进程模型帮助启用多处理器计算机上的可伸缩性,方法是将工作分发给多个进程(每个 CPU 一个),并且每个进程都将处理器关联设置为一个 CPU。此技术称为网络园艺。如果应用程序使用较慢的数据库服务器或调用具有外部依赖项的 COM 对象(这里只是提及两种可能性),则为您的应用程序启用网络园艺是有益的。但是,在决定对生产网站启用网络园艺之前,您应该测试应用程序在网络园中的执行情况。

禁用调试模式   在部署生产应用程序或进行任何性能测量之前,始终禁用调试模式。如果启用了调试模式,应用程序的性能可能受到影响。有关设置调试模式的语法信息,请参见编辑 ASP.NET 配置文件。

优化 Web 服务器计算机和特定应用程序的配置文件以符合您的需要   默认情况下,ASP.NET 配置被设置成启用最广泛的功能集并尽量适应最常见的情况。可更改某些默认配置设置以提高应用程序的性能,具体取决于您使用的功能。下面的列表包含您应考虑的配置设置:

仅对需要的应用程序启用身份验证   默认情况下,ASP.NET 应用程序的身份验证模式为 Windows 或集成的 NTLM。大多数情况下,最好仅对需要身份验证的应用程序在 Machine.config 文件中禁用身份验证,并在 Web.config 文件中启用身份验证。

根据适当的请求和响应编码设置来配置应用程序   ASP.NET 默认编码格式为 UTF-8。如果您的应用程序仅使用 ASCII 字符,请配置您的 ASCII 应用程序以获得稍许的性能提高。

考虑对应用程序禁用 AutoEventWireup   在 Machine.config 文件中将 AutoEventWireup 属性设置为 false,意味着页面不会将页事件绑定到基于名称匹配的方法(例如 Page_Load)。如果禁用 AutoEventWireup,页面将通过将事件连接留给您而不是自动执行它,获得稍许的性能提升。

如果您要处理页事件,需要在基类中重写方法(例如,需要为页加载事件重写 Page 对象的 OnLoad 方法,而不是使用 Page_Load 方法)。

从请求处理管线中移除不用的模块   默认情况下,服务器计算机的 Machine.config 文件中 HttpModules 节点的所有功能均保留为活动状态。根据应用程序所使用的功能,您可以从请求管线中移除不用的模块以获得稍许的性能提升。检查每个模块及其功能,并按您的需要自定义它。

例如,如果您在应用程序中不使用会话状态和输出缓存,则可以从 HttpModules 列表中移除它们,以便请求在不执行其他有意义的处理时,不必调用这些模块。

编码实践

不要依赖代码中的异常   异常会大大地降低性能,所以您应该避免将它们用作控制正常程序流的方式。如果有可能检测到代码中可能导致异常的状态,请执行这种操作,而不要捕捉异常本身和处理该状态。常见的代码检测方案包括:检查 null,将一个值分配给将分析为数值的 String,或在应用数学运算前检查特定值。
适当地使用公共语言运行库的垃圾回收器和自动内存管理   注意不要对每个请求使用过多内存(如在内存中存储大型对象或数据集),因为这样垃圾回收器将必须更频繁地进行更多的工作。同样,当不再需要对象时,请不要在代码中保留不必要的对象引用,因为在它们仍然被引用的情况下,垃圾回收器将无法释放资源。

尽量避免使用含 Finalize 方法的对象,因为它们在后面会导致更多垃圾回收器工作。特别是在对 Finalize 的调用中永远不要释放资源,因为资源在垃圾回收器调用其 Finalize 方法之前可能一直消耗着内存。最后这个问题经常会对 Web 服务器环境的性能造成毁灭性的打击,因为在等待 Finalize 运行时,很容易耗尽某个给定资源的可用性。

有关垃圾回收器和自动内存管理的更多信息,请参见自动内存管理。

在托管代码中重写调用密集型的 COM 组件   .NET Framework 提供了一个简单的方法与传统的 COM 组件进行交互。其优点是可以在保留现有 COM 组件投资的同时利用 .NET 的功能。但是在某些情况下,保留旧组件的性能开销使得将组件迁移到托管代码是值得的。每一情况都是不一样的,决定是否需要迁移组件的最好方法是对网站运行性能测量。建议您研究一下如何将经常调用的任何 COM 组件迁移到托管代码。

许多情况下不可能将旧式组件迁移到托管代码,特别是在最初迁移 Web 应用程序时。在这种情况下,最大的性能障碍之一是将数据从非托管环境封送到托管环境。因此,在交互操作中,请在任何一端执行尽可能多的任务,然后进行单个调用而不是一系列小调用。例如,公共语言运行库中的所有字符串都是 Unicode 的,所以应在调用托管代码之前将组件中的所有字符串转换成 Unicode 格式。

一旦处理完任何 COM 对象或本机资源就释放它们。这样,其他请求就能够使用它们,并且最大限度地减少了因稍后请求垃圾回收器释放它们所引起的性能问题。

避免单线程单元 (STA) COM 组件   默认情况下,ASP.NET 不允许 STA COM 组件在页内运行。若要运行它们,必须在 .aspx 文件内将 ASPCompat=true 属性包含在 @ Page 指令中。这样就将页执行用的线程池切换到 STA 线程池,而且使 HttpContext 和其他内置对象可用于 COM 对象。避免使用 STA COM 组件是一种性能优化,因为它避免了将多线程单元 (MTA) 封送到 STA 线程的任何调用。

如果必须使用 STA COM 组件,则应避免在执行期间进行大量调用,并尝试在每次调用期间发送尽可能多的信息。另外,避免在构造页面期间创建 STA COM 组件。例如在下面的代码中,在页面构造时将实例化由某个线程创建的 SampleSTAComponent,而该线程并不是运行页面的 STA 线程。这可能对性能有不利影响,因为要构造页面就需要在 MTA 和 STA 线程之间进行封送处理。
推荐的做法是仅在需要时或者在 Page_Load 方法中构造 COM 组件和外部资源。

永远不要将 STA COM 组件存储在可以由构造它们的线程以外的其他线程访问的共享资源(如缓存或会话状态)里。即使 STA 线程调用 STA COM 组件,也只有构造此 STA COM 组件的线程能够为该调用服务,而这要求封送处理对创建者线程的调用。此封送处理可能产生重大的性能损失和可伸缩性问题。在这种情况下,请考虑使 COM 组件成为 MTA COM 组件或在托管代码中重写该组件。

 

原文

这些内容来自微软MSDN,首先我简单整理了一下,第二,加入了一些自己的看法,如果有不对的地方,还请大家一起讨论: 页面和服务器控件处理 避免到服务器的不必要的往返行程   在某些情况下不必

------分隔线----------------------------