ASP.NET页面优化:性能提升8倍的方法

阅读目录

创新互联公司服务项目包括崇阳网站建设、崇阳网站制作、崇阳网页制作以及崇阳网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,崇阳网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到崇阳省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!


  1. 开始
  2. 测试背景
  3. 测试方法
  4. 测试用例1:WebFromPage.aspx
  5. 测试用例2:InlinePage.aspx
  6. 分析优化结果1
  7. 测试用例3:InlineUserControl.ascx
  8. 分析优化结果2

今天与大家分享:一种优化页面执行速度的方法。

采用这个方法,可以使用页面的执行速度获得【8倍】的提升效果。

为了让您对优化的效果有个直观的了解,我准备了下面的测试结果截图:

测试环境:

  1. Windows Server 2003 SP2
  2. Viaual Studio 2008,使用自带的WebDev.WebServer.EXE运行网站程序。
  3. (ThinkPad SL510):Core2 T6670 2.2GHz, 4G内存

二个红框中的数字反映了优化前后的执行时间。

数字表明:优化前后,执行时间有了8倍多的差别。

本文的测试结果也仅仅只是一个参考数字,这个结果也只是根据我所设计的测试页面得出的。

优化的过程中,如果不使用服务器控件,那么给GC减少的压力其实也是无法测试到的。

在测试过程中,我还发现测试结果并不是很稳定,因此截图具有一定的偶然性。

测试页面或许在某些方面存在一些片面性,因此,结果仅供参考。

测试背景

看过了优化结果,再来介绍一下:这个测试到底是在测试什么东西?

现在有很多做ASP.NET的开发人员,应该都是从ASP.NET的WebForm编程模型开始学习的。大家都很喜欢用服务器控件,不管输出什么,都会使用服务器控件。有时候为了让页面呈现干净的HTML代码,有些人会选择使用Repeater,Literal这类简单的服务器控件。或许有些人认为:我已不使用GridView这样强大复杂的控件,页面执行速度已经很快了。

真是这样吗?

今天测试的起点就从使用简单的服务器开始,我会分二次对它做一系列的性能优化。

最终就是上图中的3个结果,它们反映了二次优化的改进过程。

在继续介绍之前,有一点我想有必要说明一下:

优化的过程涉及到ASP.NET服务器控件的使用,测试结果也仅仅只是一个参考数字。

如果您认为您的开发工作非常依赖于服务器控件的使用,

那么测试结果对您来说其实是无意义的,请不要在意这个结果。

测试方法

在这次优化过程中,我并没有设计很复杂的测试页面,而是一个很简单的测试页面,页面显示效果如下:

这个页面其实就是显示了一堆超链接,它们来自于我的博客侧边栏的【推荐排行榜】,总共有20条记录,我让页面重复5次输出,也就是生成了100个超链接。

测试的数据是这样获取的:

我复制了我的博客侧边栏的【推荐排行榜】的那段HTML代码,保存到一个文件中:

然后,网站在初始化时,从这段HTML代码提取链接地址以及显示文字,保存到一个BlogInfo的列表中,代码如下:

 
 
 
 
  1. public class BlogInfo  
  2. {  
  3.     public string Title;  
  4.     public string Href;  
  5. }  
  6.  
  7. public static class XmlDb  
  8. {  
  9.     public static List Blogs { get; private set; }  
  10.  
  11.  
  12.     public static void LoadBlogs()  
  13.     {  
  14.         string filePath = Path.Combine(HttpRuntime.AppDomainAppPath, @"App_Data\RecommendList.html");  
  15.  
  16.         XElement html = XElement.Parse(System.IO.File.ReadAllText(filePath));  
  17.  
  18.         Blogs =  
  19.             (from a in html.Elements("li").Elements("a")  
  20.              select new BlogInfo { Title = a.Value, Href = a.Attribute("href").Value }).ToList();  
  21.     }  

测试时,就把XmlDb.Blogs的内容显示在网页中。
我想这个测试还是比较接近于现实开发的。

这里又有一个问题:我如何测试页面的执行速度?

虽然说创建HttpWebRequest访问页面是个很简单的方法,但我并不打算这样做。
因为从HttpWebRequest发起调用到获取结果,这其中除了有页面的执行时间,还混杂较多的额外调用开销。最终,我选择了在一次HTTP请求中,循环调用Server.Execute来执行页面,并统计时间的方式。其实如何选择测试方法,对于二个测试对象还说,都是公平的。只是说:尽量减少一些额外的调用开销,会让测试结果的差异更大,也更明显。

说明:为了测试代码写起来简单,我使用了MyMVC框架。

测试用例1:WebFromPage.aspx

前面介绍了测试背景以及测试方法。现在就来介绍第1个测试用例,它采用了WebForm编程模型中最经典的写法。

页面代码:

 
 
 
 
  1. <%@ Page Language="C#" CodeFile="WebFromPage.aspx.cs" Inherits="TestPage_WebFromPage" %> 
  2.  
  3.  
  4.  
  5.     PagePerformanceTest   http://www.cnblogs.com/fish-li/ 
  6.  
  7.  
  8.  
  9. This is WebFromPage.aspx

     
  10.  
  11.  
  12.  
  13.      
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20.      
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.      
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.      
  35.  
  36.  
  37.  
  38.  
  39.  
  40.  
  41.      
  42.  
  43.  
  44.  
  45.  
  46.  
  47.  
  48.  

页面的CodeFile代码:

 
 
 
 
  1. public partial class TestPage_WebFromPage : System.Web.UI.Page  
  2. {  
  3.     protected override void OnLoad(EventArgs e)  
  4.     {  
  5.         base.OnLoad(e);  
  6.  
  7.         repeater1.DataSource = XmlDb.Blogs;  
  8.         repeater1.DataBind();  
  9.         repeater2.DataSource = XmlDb.Blogs;  
  10.         repeater2.DataBind();  
  11.         repeater3.DataSource = XmlDb.Blogs;  
  12.         repeater3.DataBind();  
  13.         repeater4.DataSource = XmlDb.Blogs;  
  14.         repeater4.DataBind();  
  15.         repeater5.DataSource = XmlDb.Blogs;  
  16.         repeater5.DataBind();  
  17.     }  
  18.  
  19.     protected void repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)  
  20.     {  
  21.         if( e.Item.ItemType == ListItemType.Item ) {  
  22.             BlogInfo blog = e.Item.DataItem as BlogInfo;  
  23.             HyperLink link1 = e.Item.FindControl("link1") as HyperLink;  
  24.             link1.NavigateUrl = blog.Href;  
  25.             link1.Text = blog.Title;  
  26.         }  
  27.     }  

测试代码:

 
 
 
 
  1. [Action]  
  2. public object Test1(string callTimes)  
  3. {  
  4.     int count = 0;  
  5.     int.TryParse(callTimes, out count);  
  6.     if( count <= 0 )  
  7.         return count;  
  8.  
  9.     HttpContext context = HttpContext.Current;  
  10.       
  11.     // 先执行一次,排除编译时间  
  12.     string html = MyMVC.PageExecutor.Render(context, "/TestPage/WebFromPage.aspx", null);  
  13.  
  14.     Stopwatch watch = Stopwatch.StartNew();  
  15.     for( int i = 0; i < count; i++ )  
  16.         html = MyMVC.PageExecutor.Render(context, "/TestPage/WebFromPage.aspx", null);  
  17.     watch.Stop();  
  18.  
  19.     return watch.Elapsed.ToString();  

当我测试执行10000次时,耗时:00:00:07.5607229

测试用例2:InlinePage.aspx

与测试用例1不同,测试用例2则完全不使用服务器控件。

页面代码:

 
 
 
 
  1. <%@ Page Language="C#" %> 
  2.  
  3.  
  4.  
  5.     PagePerformanceTest   http://www.cnblogs.com/fish-li/ 
  6.  
  7.  
  8.  
  9. This is InlinePage.aspx

     
  10.  
  11. <% foreach( BlogInfo b in XmlDb.Blogs ) { %> 
  12.     " target="_blank"><%= b.Title %> 
  13. <% } %> 
  14.  
  15.  
  16. <% foreach( BlogInfo b in XmlDb.Blogs ) { %> 
  17.     " target="_blank"><%= b.Title %> 
  18. <% } %> 
  19.  
  20.  
  21. <% foreach( BlogInfo b in XmlDb.Blogs ) { %> 
  22.     " target="_blank"><%= b.Title %> 
  23. <% } %> 
  24.  
  25.  
  26. <% foreach( BlogInfo b in XmlDb.Blogs ) { %> 
  27.     " target="_blank"><%= b.Title %> 
  28. <% } %> 
  29.  
  30.  
  31. <% foreach( BlogInfo b in XmlDb.Blogs ) { %> 
  32.     " target="_blank"><%= b.Title %> 
  33. <% } %> 
  34.  
  35.  
  36.  
  37.  

测试代码:

 
 
 
 
  1. [Action]  
  2. public object Test2(string callTimes)  
  3. {  
  4.     int count = 0;  
  5.     int.TryParse(callTimes, out count);  
  6.     if( count <= 0 )  
  7.         return count;  
  8.  
  9.     HttpContext context = HttpContext.Current;  
  10.  
  11.     // 先执行一次,排除编译时间  
  12.     string html = MyMVC.PageExecutor.Render(context, "/TestPage/InlinePage.aspx", null);  
  13.  
  14.     Stopwatch watch = Stopwatch.StartNew();  
  15.     for( int i = 0; i < count; i++ )  
  16.         html = MyMVC.PageExecutor.Render(context, "/TestPage/InlinePage.aspx", null);  
  17.     watch.Stop();  
  18.  
  19.     return watch.Elapsed.ToString();  

当我测试执行10000次时,耗时:00:00:01.2345842

分析优化结果1

测试用例1执行相同次数所花费的时间是测试用例2的6倍,为什么会这样呢?

为了回答这个问题,我们首先要知道前面二个页面在执行时,它们是如何运行的。

说到这里,就不得不谈ASP.NET的页面编译方式了。

ASP.NET的页面编译过程是个复杂的操作,其实我们可以不用关心页面是如何编译的,但要知道:页面编译后是什么样的。

为了能直观地了解页面编译后的样子,我编译了整个网站,并生成到一个DLL文件中,然后使用Reflector.exe来分析这个DLL的源代码。

将网站编译成一个DLL文件有二个方法:

  1. 安装WebDeployment插件。
  2. 使用我的工具:FishAspnetTool

本文将使用FishAspnetTool来编译测试网站获得编译后的DLL文件。

FishAspnetTool是什么?

FishAspnetTool是我在使用Visual Web Developer 2005时,为了方便编译网站而写的一个小工具。

下载地址:http://www.cnblogs.com/fish-li/archive/2011/10/30/2229497.html

注意:下载的是一个工具包,安装后,从开始菜单中运行FishTools\FishAspnetTool即可。

下面是工具的运行截图。

操作方法:

1. 点击粉色按钮,选择网站路径。

2. 单选按钮选择第2项。

3. 点击【发布网站】按钮。

在编译网站之后,我就可以知道网站在运行时如何运行页面了。

测试用例1的页面,最后被编译成这样了:

 
 
 
 
  1. namespace ASP  
  2. {  
  3.     using System;  
  4.     using System.Diagnostics;  
  5.     using System.Runtime.CompilerServices;  
  6.     using System.Web;  
  7.     using System.Web.UI;  
  8.     using System.Web.UI.WebControls;  
  9.  
  10.     [CompilerGlobalScope]  
  11.     public class testpage_webfrompage_aspx : TestPage_WebFromPage, IHttpHandler  
  12.     {  
  13.         private static object __fileDependencies;  
  14.         private static bool __initialized;  
  15.  
  16.         [DebuggerNonUserCode]  
  17.         public testpage_webfrompage_aspx()  
  18.         {  
  19.             base.AppRelativeVirtualPath = "~/TestPage/WebFromPage.aspx";  
  20.             if (!__initialized)  
  21.             {  
  22.                 string[] virtualFileDependencies = new string[] { "~/TestPage/WebFromPage.aspx", "~/TestPage/WebFromPage.aspx.cs" };  
  23.                 __fileDependencies = base.GetWrappedFileDependencies(virtualFileDependencies);  
  24.                 __initialized = true;  
  25.             }  
  26.             base.Server.ScriptTimeout = 0x1c9c380;  
  27.         }  
  28.  
  29.         [DebuggerNonUserCode]  
  30.         private void __BuildControl__control10(Control __ctrl)  
  31.         {  
  32.             IParserAccessor accessor = __ctrl;  
  33.             accessor.AddParsedSubObject(new LiteralControl(""));  
  34.         }  
  35.  
  36.         [DebuggerNonUserCode]  
  37.         private void __BuildControl__control11(Control __ctrl)  
  38.         {  
  39.             IParserAccessor accessor = __ctrl;  
  40.             accessor.AddParsedSubObject(new LiteralControl("\r\n\t"));  
  41.             HyperLink link = this.__BuildControl__control12();  
  42.             accessor.AddParsedSubObject(link);  
  43.             accessor.AddParsedSubObject(new LiteralControl("\r\n"));  
  44.         }  
  45.  
  46.         [DebuggerNonUserCode]  
  47.         private HyperLink __BuildControl__control12()  
  48.         {  
  49.             HyperLink link = new HyperLink {  
  50.                 TemplateControl = this 
  51.             };  
  52.             link.ApplyStyleSheetSkin(this);  
  53.             link.ID = "link1";  
  54.             return link;  
  55.         }  
  56.  
  57.         [DebuggerNonUserCode]  
  58.         private void __BuildControl__control13(Control __ctrl)  
  59.         {  
  60.             IParserAccessor accessor = __ctrl;  
  61.             accessor.AddParsedSubObject(new LiteralControl(""));  
  62.         }  
  63.  
  64.         [DebuggerNonUserCode]  
  65.         private void __BuildControl__control14(Control __ctrl)  
  66.         {  
  67.             IParserAccessor accessor = __ctrl;  
  68.             accessor.AddParsedSubObject(new LiteralControl("\r\n\t"));  
  69.             HyperLink link = this.__BuildControl__control15();  
  70.             accessor.AddParsedSubObject(link);  
  71.             accessor.AddParsedSubObject(new LiteralControl("\r\n"));  
  72.         }  
  73.  
  74.         [DebuggerNonUserCode]  
  75.         private HyperLink __BuildControl__control15()  
  76.         {  
  77.             HyperLink link = new HyperLink {  
  78.                 TemplateControl = this 
  79.             };  
  80.             link.ApplyStyleSheetSkin(this);  
  81.             link.ID = "link1";  
  82.             return link;  
  83.         }  
  84.  
  85.         [DebuggerNonUserCode]  
  86.         private void __BuildControl__control16(Control __ctrl)  
  87.         {  
  88.             IParserAccessor accessor = __ctrl;  
  89.             accessor.AddParsedSubObject(new LiteralControl(""));  
  90.         }  
  91.  
  92.         [DebuggerNonUserCode]  
  93.         private void __BuildControl__control2(Control __ctrl)  
  94.         {  
  95.             IParserAccessor accessor = __ctrl;  
  96.             accessor.AddParsedSubObject(new LiteralControl("\r\n\t"));  
  97.             HyperLink link = this.__BuildControl__control3();  
  98.             accessor.AddParsedSubObject(link);  
  99.             accessor.AddParsedSubObject(new LiteralControl("\r\n"));  
  100.         }  
  101.  
  102.         [DebuggerNonUserCode]  
  103.         private HyperLink __BuildControl__control3()  
  104.         {  
  105.             HyperLink link = new HyperLink {  
  106.                 TemplateControl = this 
  107.             };  
  108.             link.ApplyStyleSheetSkin(this);  
  109.             link.ID = "link1";  
  110.             return link;  
  111.         }  
  112.  
  113.         [DebuggerNonUserCode]  
  114.         private void __BuildControl__control4(Control __ctrl)  
  115.         {  
  116.             IParserAccessor accessor = __ctrl;  
  117.             accessor.AddParsedSubObject(new LiteralControl(""));  
  118.         }  
  119.  
  120.         [DebuggerNonUserCode]  
  121.         private void __BuildControl__control5(Control __ctrl)  
  122.         {  
  123.             IParserAccessor accessor = __ctrl;  
  124.             accessor.AddParsedSubObject(new LiteralControl("\r\n\t"));  
  125.             HyperLink link = this.__BuildControl__control6();  
  126.             accessor.AddParsedSubObject(link);  
  127.             accessor.AddParsedSubObject(new LiteralControl("\r\n"));  
  128.         }  
  129.  
  130.         [DebuggerNonUserCode]  
  131.         private HyperLink __BuildControl__control6()  
  132.         {  
  133.             HyperLink link = new HyperLink {  
  134.                 TemplateControl = this 
  135.             };  
  136.             link.ApplyStyleSheetSkin(this);  
  137.             link.ID = "link1";  
  138.             return link;  
  139.         }  
  140.  
  141.         [DebuggerNonUserCode]  
  142.         private void __BuildControl__control7(Control __ctrl)  
  143.         {  
  144.             IParserAccessor accessor = __ctrl;  
  145.             accessor.AddParsedSubObject(new LiteralControl(""));  
  146.         }  
  147.  
  148.         [DebuggerNonUserCode]  
  149.         private void __BuildControl__control8(Control __ctrl)  
  150.         {  
  151.             IParserAccessor accessor = __ctrl;  
  152.             accessor.AddParsedSubObject(new LiteralControl("\r\n\t"));  
  153.             HyperLink link = this.__BuildControl__control9();  
  154.             accessor.AddParsedSubObject(link);  
  155.             accessor.AddParsedSubObject(new LiteralControl("\r\n"));  
  156.         }  
  157.  
  158.         [DebuggerNonUserCode]  
  159.         private HyperLink __BuildControl__control9()  
  160.         {  
  161.             HyperLink link = new HyperLink {  
  162.                 TemplateControl = this 
  163.             };  
  164.             link.ApplyStyleSheetSkin(this);  
  165.             link.ID = "link1";  
  166.             return link;  
  167.         }  
  168.  
  169.         [DebuggerNonUserCode]  
  170.         private Repeater __BuildControlrepeater1()  
  171.         {  
  172.             Repeater repeater = new Repeater();  
  173.             base.repeater1 = repeater;  
  174.             repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control2));  
  175.             repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control4));  
  176.             repeater.ID = "repeater1";  
  177.             repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound);  
  178.             return repeater;  
  179.         }  
  180.  
  181.         [DebuggerNonUserCode]  
  182.         private Repeater __BuildControlrepeater2()  
  183.         {  
  184.             Repeater repeater = new Repeater();  
  185.             base.repeater2 = repeater;  
  186.             repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control5));  
  187.             repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control7));  
  188.             repeater.ID = "repeater2";  
  189.             repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound);  
  190.             return repeater;  
  191.         }  
  192.  
  193.         [DebuggerNonUserCode]  
  194.         private Repeater __BuildControlrepeater3()  
  195.         {  
  196.             Repeater repeater = new Repeater();  
  197.             base.repeater3 = repeater;  
  198.             repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control8));  
  199.             repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control10));  
  200.             repeater.ID = "repeater3";  
  201.             repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound);  
  202.             return repeater;  
  203.         }  
  204.  
  205.         [DebuggerNonUserCode]  
  206.         private Repeater __BuildControlrepeater4()  
  207.         {  
  208.             Repeater repeater = new Repeater();  
  209.             base.repeater4 = repeater;  
  210.             repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control11));  
  211.             repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control13));  
  212.             repeater.ID = "repeater4";  
  213.             repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound);  
  214.             return repeater;  
  215.         }  
  216.  
  217.         [DebuggerNonUserCode]  
  218.         private Repeater __BuildControlrepeater5()  
  219.         {  
  220.             Repeater repeater = new Repeater();  
  221.             base.repeater5 = repeater;  
  222.             repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control14));  
  223.             repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control16));  
  224.             repeater.ID = "repeater5";  
  225.             repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound);  
  226.  

    网站题目:ASP.NET页面优化:性能提升8倍的方法
    路径分享:http://www.36103.cn/qtweb/news26/15726.html

    网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

    广告

    声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联