时间:2021-07-01 10:21:17 帮助过:33人阅读
- <br>public class BlogInfo <br>{ <br>public string Title; <br>public string Href; <br>} <br><br>public static class XmlDb <br>{ <br>public static List<BlogInfo> Blogs { get; private set; } <br><br><br>public static void LoadBlogs() <br>{ <br>string filePath = Path.Combine(HttpRuntime.AppDomainAppPath, @"App_Data\RecommendList.html"); <br><br>XElement html = XElement.Parse(System.IO.File.ReadAllText(filePath)); <br><br>Blogs = <br>(from a in html.Elements("li").Elements("a") <br>select new BlogInfo { Title = a.Value, Href = a.Attribute("href").Value }).ToList(); <br>} <br>} <br> <br>测试时,就把XmlDb.Blogs的内容显示在网页中。 <br>我想这个测试还是比较接近于现实开发的。 <br><br>这里又有一个问题:我如何测试页面的执行速度? <br><br>虽然说创建HttpWebRequest访问页面是个很简单的方法,但我并不打算这样做。 <br>因为从HttpWebRequest发起调用到获取结果,这其中除了有页面的执行时间,还混杂较多的额外调用开销。最终,我选择了在一次HTTP请求中,循环调用Server.Execute来执行页面,并统计时间的方式。其实如何选择测试方法,对于二个测试对象还说,都是公平的。只是说:尽量减少一些额外的调用开销,会让测试结果的差异更大,也更明显。 <br><br>说明:为了测试代码写起来简单,我使用了MyMVC框架。 <br><strong>测试用例1:WebFromPage.aspx <br></strong>前面介绍了测试背景以及测试方法。现在就来介绍第1个测试用例,它采用了WebForm编程模型中最经典的写法。 <br>页面代码: <br><span><u></u></span> 代码如下:<pre class="brush:php;toolbar:false layui-box layui-code-view layui-code-notepad"><ol class="layui-code-ol"><li><br><%@ Page Language="C#" CodeFile="WebFromPage.aspx.cs" Inherits="TestPage_WebFromPage" %> <br><html xmlns="http://www.w3.org/1999/xhtml"> <br><head> <br><title>PagePerformanceTest http://www.cnblogs.com/fish-li/</title> <br></head> <br><body> <br><p>This is WebFromPage.aspx</p> <br><asp:Repeater ID="repeater1" runat="server" onitemdatabound="repeater1_ItemDataBound"> <br><ItemTemplate> <br><asp:HyperLink ID="link1" runat="server"></asp:HyperLink><br /> <br></ItemTemplate> <br><FooterTemplate><hr /></FooterTemplate> <br></asp:Repeater> <br><asp:Repeater ID="repeater2" runat="server" onitemdatabound="repeater1_ItemDataBound"> <br><ItemTemplate> <br><asp:HyperLink ID="link1" runat="server"></asp:HyperLink><br /> <br></ItemTemplate> <br><FooterTemplate><hr /></FooterTemplate> <br></asp:Repeater> <br><asp:Repeater ID="repeater3" runat="server" onitemdatabound="repeater1_ItemDataBound"> <br><ItemTemplate> <br><asp:HyperLink ID="link1" runat="server"></asp:HyperLink><br /> <br></ItemTemplate> <br><FooterTemplate><hr /></FooterTemplate> <br></asp:Repeater> <br><asp:Repeater ID="repeater4" runat="server" onitemdatabound="repeater1_ItemDataBound"> <br><ItemTemplate> <br><asp:HyperLink ID="link1" runat="server"></asp:HyperLink><br /> <br></ItemTemplate> <br><FooterTemplate><hr /></FooterTemplate> <br></asp:Repeater> <br><asp:Repeater ID="repeater5" runat="server" onitemdatabound="repeater1_ItemDataBound"> <br><ItemTemplate> <br><asp:HyperLink ID="link1" runat="server"></asp:HyperLink><br /> <br></ItemTemplate> <br><FooterTemplate><hr /></FooterTemplate> <br></asp:Repeater> <br><br></body> <br></html> <br> <br>页面的CodeFile代码: <br><span><u></u></span> 代码如下:<pre class="brush:php;toolbar:false layui-box layui-code-view layui-code-notepad"><ol class="layui-code-ol"><li><br>public partial class TestPage_WebFromPage : System.Web.UI.Page <br>{ <br>protected override void OnLoad(EventArgs e) <br>{ <br>base.OnLoad(e); <br>repeater1.DataSource = XmlDb.Blogs; <br>repeater1.DataBind(); <br>repeater2.DataSource = XmlDb.Blogs; <br>repeater2.DataBind(); <br>repeater3.DataSource = XmlDb.Blogs; <br>repeater3.DataBind(); <br>repeater4.DataSource = XmlDb.Blogs; <br>repeater4.DataBind(); <br>repeater5.DataSource = XmlDb.Blogs; <br>repeater5.DataBind(); <br>} <br>protected void repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e) <br>{ <br>if( e.Item.ItemType == ListItemType.Item ) { <br>BlogInfo blog = e.Item.DataItem as BlogInfo; <br>HyperLink link1 = e.Item.FindControl("link1") as HyperLink; <br>link1.NavigateUrl = blog.Href; <br>link1.Text = blog.Title; <br>} <br>} <br>} <br> <br>测试代码: <br><span><u></u></span> 代码如下:<pre class="brush:php;toolbar:false layui-box layui-code-view layui-code-notepad"><ol class="layui-code-ol"><li><br>[Action] <br>public object Test1(string callTimes) <br>{ <br>int count = 0; <br>int.TryParse(callTimes, out count); <br>if( count <= 0 ) <br>return count; <br>HttpContext context = HttpContext.Current; <br>// 先执行一次,排除编译时间 <br>string html = MyMVC.PageExecutor.Render(context, "/TestPage/WebFromPage.aspx", null); <br>Stopwatch watch = Stopwatch.StartNew(); <br>for( int i = 0; i < count; i++ ) <br>html = MyMVC.PageExecutor.Render(context, "/TestPage/WebFromPage.aspx", null); <br>watch.Stop(); <br>return watch.Elapsed.ToString(); <br>} <br> <br>当我测试执行10000次时,耗时:00:00:07.5607229 <br>回到顶部 <br>测试用例2:InlinePage.aspx <br>与测试用例1不同,测试用例2则完全不使用服务器控件。 <br>页面代码: <br><span><u></u></span> 代码如下:<pre class="brush:php;toolbar:false layui-box layui-code-view layui-code-notepad"><ol class="layui-code-ol"><li><br><%@ Page Language="C#" %> <br><html xmlns="http://www.w3.org/1999/xhtml"> <br><head> <br><title>PagePerformanceTest http://www.cnblogs.com/fish-li/</title> <br></head> <br><body> <br><p>This is InlinePage.aspx</p> <br><% foreach( BlogInfo b in XmlDb.Blogs ) { %> <br><a href="<%= b.Href %>" target="_blank"><%= b.Title %></a><br /> <br><% } %> <br><hr /> <br><% foreach( BlogInfo b in XmlDb.Blogs ) { %> <br><a href="<%= b.Href %>" target="_blank"><%= b.Title %></a><br /> <br><% } %> <br><hr /> <br><% foreach( BlogInfo b in XmlDb.Blogs ) { %> <br><a href="<%= b.Href %>" target="_blank"><%= b.Title %></a><br /> <br><% } %> <br><hr /> <br><% foreach( BlogInfo b in XmlDb.Blogs ) { %> <br><a href="<%= b.Href %>" target="_blank"><%= b.Title %></a><br /> <br><% } %> <br><hr /> <br><% foreach( BlogInfo b in XmlDb.Blogs ) { %> <br><a href="<%= b.Href %>" target="_blank"><%= b.Title %></a><br /> <br><% } %> <br><hr /> <br></body> <br></html> <br> <br>测试代码: <br><span><u></u></span> 代码如下:<pre class="brush:php;toolbar:false layui-box layui-code-view layui-code-notepad"><ol class="layui-code-ol"><li><br>[Action] <br>public object Test2(string callTimes) <br>{ <br>int count = 0; <br>int.TryParse(callTimes, out count); <br>if( count <= 0 ) <br>return count; <br>HttpContext context = HttpContext.Current; <br>// 先执行一次,排除编译时间 <br>string html = MyMVC.PageExecutor.Render(context, "/TestPage/InlinePage.aspx", null); <br>Stopwatch watch = Stopwatch.StartNew(); <br>for( int i = 0; i < count; i++ ) <br>html = MyMVC.PageExecutor.Render(context, "/TestPage/InlinePage.aspx", null); <br>watch.Stop(); <br>return watch.Elapsed.ToString(); <br>} <br> <br>当我测试执行10000次时,耗时:00:00:01.2345842 <br>回到顶部 <br>分析优化结果1 <br>测试用例1执行相同次数所花费的时间是测试用例2的6倍,为什么会这样呢? <br>为了回答这个问题,我们首先要知道前面二个页面在执行时,它们是如何运行的。 <br>说到这里,就不得不谈ASP.NET的页面编译方式了。 <br>ASP.NET的页面编译过程是个复杂的操作,其实我们可以不用关心页面是如何编译的, <br>但要知道:页面编译后是什么样的。 <br>为了能直观地了解页面编译后的样子,我编译了整个网站,并生成到一个DLL文件中,然后使用Reflector.exe来分析这个DLL的源代码。 <br>将网站编译成一个DLL文件有二个方法: <br>1. 安装WebDeployment插件。 <br>2. 使用我的工具:FishAspnetTool <br>本文将使用FishAspnetTool来编译测试网站获得编译后的DLL文件。 <br>FishAspnetTool是什么? <br>FishAspnetTool是我在使用Visual Web Developer 2005时,为了方便编译网站而写的一个小工具。 <br>下载地址://www.gxlcms.com/article/29875.htm <br>注意:下载的是一个工具包,安装后,从开始菜单中运行FishTools\FishAspnetTool即可。 <br>下面是工具的运行截图。 <br><img src="https://img.gxlcms.com//Uploads-s/new/2019-09-19-201919/20120311221453491.png" border="0"><br>操作方法: <br>1. 点击粉色按钮,选择网站路径。 <br>2. 单选按钮选择第2项。 <br>3. 点击【发布网站】按钮。 <br>在编译网站之后,我就可以知道网站在运行时如何运行页面了。 <br>测试用例1的页面,最后被编译成这样了: <br><span><u></u></span> 代码如下:<pre class="brush:php;toolbar:false layui-box layui-code-view layui-code-notepad"><ol class="layui-code-ol"><li><br>namespace ASP <br>{ <br>using System; <br>using System.Diagnostics; <br>using System.Runtime.CompilerServices; <br>using System.Web; <br>using System.Web.UI; <br>using System.Web.UI.WebControls; <br>[CompilerGlobalScope] <br>public class testpage_webfrompage_aspx : TestPage_WebFromPage, IHttpHandler <br>{ <br>private static object __fileDependencies; <br>private static bool __initialized; <br>[DebuggerNonUserCode] <br>public testpage_webfrompage_aspx() <br>{ <br>base.AppRelativeVirtualPath = "~/TestPage/WebFromPage.aspx"; <br>if (!__initialized) <br>{ <br>string[] virtualFileDependencies = new string[] { "~/TestPage/WebFromPage.aspx", "~/TestPage/WebFromPage.aspx.cs" }; <br>__fileDependencies = base.GetWrappedFileDependencies(virtualFileDependencies); <br>__initialized = true; <br>} <br>base.Server.ScriptTimeout = 0x1c9c380; <br>} <br>[DebuggerNonUserCode] <br>private void __BuildControl__control10(Control __ctrl) <br>{ <br>IParserAccessor accessor = __ctrl; <br>accessor.AddParsedSubObject(new LiteralControl("<hr />")); <br>} <br>[DebuggerNonUserCode] <br>private void __BuildControl__control11(Control __ctrl) <br>{ <br>IParserAccessor accessor = __ctrl; <br>accessor.AddParsedSubObject(new LiteralControl("\r\n\t")); <br>HyperLink link = this.__BuildControl__control12(); <br>accessor.AddParsedSubObject(link); <br>accessor.AddParsedSubObject(new LiteralControl("<br />\r\n")); <br>} <br>[DebuggerNonUserCode] <br>private HyperLink __BuildControl__control12() <br>{ <br>HyperLink link = new HyperLink { <br>TemplateControl = this <br>}; <br>link.ApplyStyleSheetSkin(this); <br>link.ID = "link1"; <br>return link; <br>} <br>[DebuggerNonUserCode] <br>private void __BuildControl__control13(Control __ctrl) <br>{ <br>IParserAccessor accessor = __ctrl; <br>accessor.AddParsedSubObject(new LiteralControl("<hr />")); <br>} <br>[DebuggerNonUserCode] <br>private void __BuildControl__control14(Control __ctrl) <br>{ <br>IParserAccessor accessor = __ctrl; <br>accessor.AddParsedSubObject(new LiteralControl("\r\n\t")); <br>HyperLink link = this.__BuildControl__control15(); <br>accessor.AddParsedSubObject(link); <br>accessor.AddParsedSubObject(new LiteralControl("<br />\r\n")); <br>} <br>[DebuggerNonUserCode] <br>private HyperLink __BuildControl__control15() <br>{ <br>HyperLink link = new HyperLink { <br>TemplateControl = this <br>}; <br>link.ApplyStyleSheetSkin(this); <br>link.ID = "link1"; <br>return link; <br>} <br>[DebuggerNonUserCode] <br>private void __BuildControl__control16(Control __ctrl) <br>{ <br>IParserAccessor accessor = __ctrl; <br>accessor.AddParsedSubObject(new LiteralControl("<hr />")); <br>} <br>[DebuggerNonUserCode] <br>private void __BuildControl__control2(Control __ctrl) <br>{ <br>IParserAccessor accessor = __ctrl; <br>accessor.AddParsedSubObject(new LiteralControl("\r\n\t")); <br>HyperLink link = this.__BuildControl__control3(); <br>accessor.AddParsedSubObject(link); <br>accessor.AddParsedSubObject(new LiteralControl("<br />\r\n")); <br>} <br>[DebuggerNonUserCode] <br>private HyperLink __BuildControl__control3() <br>{ <br>HyperLink link = new HyperLink { <br>TemplateControl = this <br>}; <br>link.ApplyStyleSheetSkin(this); <br>link.ID = "link1"; <br>return link; <br>} <br>[DebuggerNonUserCode] <br>private void __BuildControl__control4(Control __ctrl) <br>{ <br>IParserAccessor accessor = __ctrl; <br>accessor.AddParsedSubObject(new LiteralControl("<hr />")); <br>} <br>[DebuggerNonUserCode] <br>private void __BuildControl__control5(Control __ctrl) <br>{ <br>IParserAccessor accessor = __ctrl; <br>accessor.AddParsedSubObject(new LiteralControl("\r\n\t")); <br>HyperLink link = this.__BuildControl__control6(); <br>accessor.AddParsedSubObject(link); <br>accessor.AddParsedSubObject(new LiteralControl("<br />\r\n")); <br>} <br>[DebuggerNonUserCode] <br>private HyperLink __BuildControl__control6() <br>{ <br>HyperLink link = new HyperLink { <br>TemplateControl = this <br>}; <br>link.ApplyStyleSheetSkin(this); <br>link.ID = "link1"; <br>return link; <br>} <br>[DebuggerNonUserCode] <br>private void __BuildControl__control7(Control __ctrl) <br>{ <br>IParserAccessor accessor = __ctrl; <br>accessor.AddParsedSubObject(new LiteralControl("<hr />")); <br>} <br>[DebuggerNonUserCode] <br>private void __BuildControl__control8(Control __ctrl) <br>{ <br>IParserAccessor accessor = __ctrl; <br>accessor.AddParsedSubObject(new LiteralControl("\r\n\t")); <br>HyperLink link = this.__BuildControl__control9(); <br>accessor.AddParsedSubObject(link); <br>accessor.AddParsedSubObject(new LiteralControl("<br />\r\n")); <br>} <br>[DebuggerNonUserCode] <br>private HyperLink __BuildControl__control9() <br>{ <br>HyperLink link = new HyperLink { <br>TemplateControl = this <br>}; <br>link.ApplyStyleSheetSkin(this); <br>link.ID = "link1"; <br>return link; <br>} <br>[DebuggerNonUserCode] <br>private Repeater __BuildControlrepeater1() <br>{ <br>Repeater repeater = new Repeater(); <br>base.repeater1 = repeater; <br>repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control2)); <br>repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control4)); <br>repeater.ID = "repeater1"; <br>repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound); <br>return repeater; <br>} <br>[DebuggerNonUserCode] <br>private Repeater __BuildControlrepeater2() <br>{ <br>Repeater repeater = new Repeater(); <br>base.repeater2 = repeater; <br>repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control5)); <br>repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control7)); <br>repeater.ID = "repeater2"; <br>repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound); <br>return repeater; <br>} <br>[DebuggerNonUserCode] <br>private Repeater __BuildControlrepeater3() <br>{ <br>Repeater repeater = new Repeater(); <br>base.repeater3 = repeater; <br>repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control8)); <br>repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control10)); <br>repeater.ID = "repeater3"; <br>repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound); <br>return repeater; <br>} <br>[DebuggerNonUserCode] <br>private Repeater __BuildControlrepeater4() <br>{ <br>Repeater repeater = new Repeater(); <br>base.repeater4 = repeater; <br>repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control11)); <br>repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control13)); <br>repeater.ID = "repeater4"; <br>repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound); <br>return repeater; <br>} <br>[DebuggerNonUserCode] <br>private Repeater __BuildControlrepeater5() <br>{ <br>Repeater repeater = new Repeater(); <br>base.repeater5 = repeater; <br>repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control14)); <br>repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control16)); <br>repeater.ID = "repeater5"; <br>repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound); <br>return repeater; <br>} <br>[DebuggerNonUserCode] <br>private void __BuildControlTree(testpage_webfrompage_aspx __ctrl) <br>{ <br>__ctrl.EnableViewState = false; <br>__ctrl.EnableViewStateMac = false; <br>this.InitializeCulture(); <br>IParserAccessor accessor = __ctrl; <br>accessor.AddParsedSubObject(new LiteralControl("\r\n\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n<head>\r\n <title>PagePerformanceTest http://www.cnblogs.com/fish-li/</title>\r\n</head>\r\n<body>\r\n\r\n<p>This is WebFromPage.aspx</p>\r\n\r\n")); <br>Repeater repeater = this.__BuildControlrepeater1(); <br>accessor.AddParsedSubObject(repeater); <br>accessor.AddParsedSubObject(new LiteralControl("\r\n\r\n")); <br>Repeater repeater2 = this.__BuildControlrepeater2(); <br>accessor.AddParsedSubObject(repeater2); <br>accessor.AddParsedSubObject(new LiteralControl("\r\n\r\n")); <br>Repeater repeater3 = this.__BuildControlrepeater3(); <br>accessor.AddParsedSubObject(repeater3); <br>accessor.AddParsedSubObject(new LiteralControl("\r\n\r\n")); <br>Repeater repeater4 = this.__BuildControlrepeater4(); <br>accessor.AddParsedSubObject(repeater4); <br>accessor.AddParsedSubObject(new LiteralControl("\r\n\r\n")); <br>Repeater repeater5 = this.__BuildControlrepeater5(); <br>accessor.AddParsedSubObject(repeater5); <br>accessor.AddParsedSubObject(new LiteralControl("\r\n\r\n\r\n</body>\r\n</html>\r\n")); <br>} <br>[DebuggerNonUserCode] <br>protected override void FrameworkInitialize() <br>{ <br>base.FrameworkInitialize(); <br>this.__BuildControlTree(this); <br>base.AddWrappedFileDependencies(__fileDependencies); <br>base.Request.ValidateInput(); <br>} <br>[DebuggerNonUserCode] <br>public override int GetTypeHashCode() <br>{ <br>return -781896338; <br>} <br>[DebuggerNonUserCode] <br>public override void ProcessRequest(HttpContext context) <br>{ <br>base.ProcessRequest(context); <br>} <br>protected override bool SupportAutoEvents <br>{ <br>get <br>{ <br>return false; <br>} <br>} <br>} <br>} <br> <br>从这个编译结果我们可以看出:页面上的所有文字最后也被包装到LiteralControl中。 <br>页面中呈现时,就是循环调用每个控件的Render方法来最终生成HTML结果。 <br>测试用例2的页面被编译成这个样了: <br><span><u></u></span> 代码如下:<pre class="brush:php;toolbar:false layui-box layui-code-view layui-code-notepad"><ol class="layui-code-ol"><li><br>namespace ASP <br>{ <br>using System; <br>using System.Diagnostics; <br>using System.Runtime.CompilerServices; <br>using System.Web; <br>using System.Web.Profile; <br>using System.Web.UI; <br>[CompilerGlobalScope] <br>public class testpage_inlinepage_aspx : Page, IHttpHandler <br>{ <br>private static object __fileDependencies; <br>private static bool __initialized; <br>[DebuggerNonUserCode] <br>public testpage_inlinepage_aspx() <br>{ <br>base.AppRelativeVirtualPath = "~/TestPage/InlinePage.aspx"; <br>if (!__initialized) <br>{ <br>string[] virtualFileDependencies = new string[] { "~/TestPage/InlinePage.aspx" }; <br>__fileDependencies = base.GetWrappedFileDependencies(virtualFileDependencies); <br>__initialized = true; <br>} <br>base.Server.ScriptTimeout = 0x1c9c380; <br>} <br>[DebuggerNonUserCode] <br>private void __BuildControlTree(testpage_inlinepage_aspx __ctrl) <br>{ <br>__ctrl.EnableViewState = false; <br>__ctrl.EnableViewStateMac = false; <br>this.InitializeCulture(); <br>__ctrl.SetRenderMethodDelegate(new RenderMethod(this.__Render__control1)); <br>} <br>private void __Render__control1(HtmlTextWriter __w, Control parameterContainer) <br>{ <br>__w.Write("\r\n\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n<head>\r\n <title>PagePerformanceTest http://www.cnblogs.com/fish-li/</title>\r\n</head>\r\n<body>\r\n\r\n<p>This is InlinePage.aspx</p>\r\n\r\n"); <br>foreach (BlogInfo info in XmlDb.Blogs) <br>{ <br>__w.Write("\r\n\t<a href=\""); <br>__w.Write(info.Href); <br>__w.Write("\" target=\"_blank\">"); <br>__w.Write(info.Title); <br>__w.Write("</a><br />\r\n"); <br>} <br>__w.Write("\r\n<hr />\r\n\r\n"); <br>foreach (BlogInfo info2 in XmlDb.Blogs) <br>{ <br>__w.Write("\r\n\t<a href=\""); <br>__w.Write(info2.Href); <br>__w.Write("\" target=\"_blank\">"); <br>__w.Write(info2.Title); <br>__w.Write("</a><br />\r\n"); <br>} <br>__w.Write("\r\n<hr />\r\n\r\n"); <br>foreach (BlogInfo info3 in XmlDb.Blogs) <br>{ <br>__w.Write("\r\n\t<a href=\""); <br>__w.Write(info3.Href); <br>__w.Write("\" target=\"_blank\">"); <br>__w.Write(info3.Title); <br>__w.Write("</a><br />\r\n"); <br>} <br>__w.Write("\r\n<hr />\r\n\r\n"); <br>foreach (BlogInfo info4 in XmlDb.Blogs) <br>{ <br>__w.Write("\r\n\t<a href=\""); <br>__w.Write(info4.Href); <br>__w.Write("\" target=\"_blank\">"); <br>__w.Write(info4.Title); <br>__w.Write("</a><br />\r\n"); <br>} <br>__w.Write("\r\n<hr />\r\n\r\n"); <br>foreach (BlogInfo info5 in XmlDb.Blogs) <br>{ <br>__w.Write("\r\n\t<a href=\""); <br>__w.Write(info5.Href); <br>__w.Write("\" target=\"_blank\">"); <br>__w.Write(info5.Title); <br>__w.Write("</a><br />\r\n"); <br>} <br>__w.Write("\r\n<hr />\r\n\r\n</body>\r\n</html>\r\n"); <br>} <br>[DebuggerNonUserCode] <br>protected override void FrameworkInitialize() <br>{ <br>base.FrameworkInitialize(); <br>this.__BuildControlTree(this); <br>base.AddWrappedFileDependencies(__fileDependencies); <br>base.Request.ValidateInput(); <br>} <br>[DebuggerNonUserCode] <br>public override int GetTypeHashCode() <br>{ <br>return -1307842476; <br>} <br>[DebuggerNonUserCode] <br>public override void ProcessRequest(HttpContext context) <br>{ <br>base.ProcessRequest(context); <br>} <br>protected global_asax ApplicationInstance <br>{ <br>get <br>{ <br>return (global_asax) this.Context.ApplicationInstance; <br>} <br>} <br>protected DefaultProfile Profile <br>{ <br>get <br>{ <br>return (DefaultProfile) this.Context.Profile; <br>} <br>} <br>protected override bool SupportAutoEvents <br>{ <br>get <br>{ <br>return false; <br>} <br>} <br>} <br>} <br> <br>请注意下面这段关键的代码:它们实在太重要了。 <br><span><u></u></span> 代码如下:<pre class="brush:php;toolbar:false layui-box layui-code-view layui-code-notepad"><ol class="layui-code-ol"><li><br>private void __BuildControlTree(testpage_inlinepage_aspx __ctrl) <br>{ <br>// ....... <br>__ctrl.SetRenderMethodDelegate(new RenderMethod(this.__Render__control1)); <br>} <br>private void __Render__control1(HtmlTextWriter __w, Control parameterContainer) <br>{ <br> <br>testpage_inlinepage_aspx与testpage_webfrompage_aspx的编译结果完全不同。 <br>最大的差别在testpage_inlinepage_aspx有个方法:__Render__control1 <br>在这个方法中,页面的内容将直接被写入到HtmlTextWriter对象中。 <br>还有一点我要告诉您:每个Control的</li></ol></pre>输出最后还是要将自己的显示代码写入到HtmlTextWriter对象中。 <br>因此,从这里就可以明显地看出testpage_inlinepage_aspx的执行速度要快很多, <br>因为: <br>1. 它没有服务器控件。 <br>2. 不再需要递归循环每个控件,每个控件的生命周期的调用开销也节省了。 <br>3. 不用再创建那些服务器控件对象,GC的压力会小很多。 <br>4. </li></ol></pre>输出方式更高效。 <br>通过前面的分析,您现在明白了为什么二个页面的执行速度相差6倍了原因了吧。 <br>好像还有一点没有解释:__Render__control1如何被调用? <br>我们都知道:以ASPX页面为代表的WebForm编程模型在执行时有一个特点:递归循环每个控件。 <br>页面是在Render阶段</li></ol></pre>输出的,页面的HTML代码也是在那个阶段</li></ol></pre>输出到HtmlTextWriter对象中的。 <br>可是,testpage_inlinepage_aspx没有任何控件,那又该如何递归呢? <br>的确,很多书籍以及技术资料都是说:在Render阶段会递归循环每个控件并调用控件的Render方法。 <br>其实这种说法是不准确的。Control的Render方法在运行时,会调用下面这个方法: <br><span><u></u></span> 代码如下:<pre class="brush:php;toolbar:false layui-box layui-code-view layui-code-notepad"><ol class="layui-code-ol"><li><br>internal void RenderChildrenInternal(HtmlTextWriter writer, ICollection children) <br>{ <br>if ((this.RareFields != null) && (this.RareFields.RenderMethod != null)) <br>{ <br>writer.BeginRender(); <br>this.RareFields.RenderMethod(writer, this); <br>writer.EndRender(); <br>} <br>else if (children != null) <br>{ <br>foreach (Control control in children) <br>{ <br>control.RenderControl(writer); <br>} <br>} <br>} <br> <br>这段代码中,有个重要的if...else...判断,简单说来,就是说要不要调用前面所说的__Render__control1方法。 <br>从代码可以看出,如果是进入了if语句块,则不用递归循环每个控件并调用控件的Render方法。 <br>那么如何能进入if语句块呢? <br>答案是:调用Control.SetRenderMethodDelegate方法。 <br>testpage_inlinepage_aspx的编译生成代码中就有这个调用。 <br>对于这个方法,MSDN的解释很含糊: <br>此 API 支持 .NET Framework 基础结构,不适合在代码中直接使用。 <br>分配事件处理程序委托,以将服务器控件及其内容呈现到父控件中。 <br>回到顶部 <br>测试用例3:InlineUserControl.ascx <br>在测试用例3中,我将页面中用于</li></ol></pre>输出的代码移到一个用户控件中。 <br>用户控件的代码此处省略,与测试用例2的代码基本上一致。编译后的结果也基本差不多。 <br>测试代码: <br><span><u></u></span> 代码如下:<pre class="brush:php;toolbar:false layui-box layui-code-view layui-code-notepad"><ol class="layui-code-ol"><li><br>[Action] <br>public object Test3(string callTimes) <br>{ <br>int count = 0; <br>int.TryParse(callTimes, out count); <br>if( count <= 0 ) <br>return count; <br>// 先执行一次,排除编译时间 <br>string html = MyMVC.UcExecutor.Render("/UserControl/InlineUserControl.ascx", null); <br>Stopwatch watch = Stopwatch.StartNew(); <br>for( int i = 0; i < count; i++ ) <br>html = MyMVC.UcExecutor.Render("/UserControl/InlineUserControl.ascx", null); <br>watch.Stop(); <br>return watch.Elapsed.ToString(); <br>} <br> <br>当我测试执行10000次时,耗时:00:00:00.9132738 <br>又快了一点。 <br>说明:为了这次的性能优化,MyMVC框架也做了一点调整。如果您以前下载过这个框架,请重新下载。 <br>回到顶部 <br>分析优化结果2 <br>经过前面的分析,我们知道:不创建服务器控件对象以及不调用它们的生命周期,可以让页面的执行速度快很多。 <br>有没有再想像一下:页面也有生命周期啊,而且生命周期的步骤更长,省略它,会不会更快呢? <br>不过,Render方法并不是个public方法,我们还不能直接调用,但可以调用RenderControl方法来实现这一过程。 <br>由于跳过页面的生命周期,任何服务器控件都不能使用了,包括母板页。所以我选择将前面测试用的那段代码移到用户控件中,然后将用户控件加载到Page中来测试。 <br>测试用例3与测试用例2相比,在测试过程中,由于跳过了页面的生命周期,因此速度也就更快了。 <br>嗯,基本上,就是这个简单的原因吧。 <br>由于这种方法没有任何的控件生命周期,因此速度是最快的。 <br>经过这一系列的优化,页面的执行时间最终由 00:00:07.5607229 减少到 00:00:00.9132738 <br><br>点击此处下载示例代码</li><li> </li><li> </li></ol></pre></li></ol></pre></li></ol></pre></li></ol></pre></li></ol></pre>