一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - ASP.NET教程 - ASP.NET頁面優化 性能提升8倍的方法

ASP.NET頁面優化 性能提升8倍的方法

2019-09-29 11:31asp.net教程網 ASP.NET教程

今天與大家分享:一種優化頁面執行速度的方法。采用這個方法,可以使用頁面的執行速度獲得【8倍】的提升效果

為了讓您對優化的效果有個直觀的了解,我準備了下面的測試結果截圖: 

ASP.NET頁面優化 性能提升8倍的方法

測試環境: 
1. Windows Server 2003 SP2 
2. Viaual Studio 2008,使用自帶的WebDev.WebServer.EXE運行網站程序。 
3. (ThinkPad SL510):Core2 T6670 2.2GHz, 4G內存 

二個紅框中的數字反映了優化前后的執行時間。 

數字表明:優化前后,執行時間有了8倍多的差別。 

測試背景 

看過了優化結果,再來介紹一下:這個測試到底是在測試什么東西? 

現在有很多做ASP.NET的開發人員,應該都是從ASP.NET的WebForm編程模型開始學習的。大家都很喜歡用服務器控件,不管輸出什么,都會使用服務器控件。有時候為了讓頁面呈現干凈的HTML代碼,有些人會選擇使用Repeater,Literal這類簡單的服務器控件。或許有些人認為:我已不使用GridView這樣強大復雜的控件,頁面執行速度已經很快了。 

真是這樣嗎? 

今天測試的起點就從使用簡單的服務器開始,我會分二次對它做一系列的性能優化。 
最終就是上圖中的3個結果,它們反映了二次優化的改進過程。 

在繼續介紹之前,有一點我想有必要說明一下: 

優化的過程涉及到ASP.NET服務器控件的使用,測試結果也僅僅只是一個參考數字。 
如果您認為您的開發工作非常依賴于服務器控件的使用, 
那么測試結果對您來說其實是無意義的,請不要在意這個結果。 
測試方法 
在這次優化過程中,我并沒有設計很復雜的測試頁面,而是一個很簡單的測試頁面,頁面顯示效果如下: 
ASP.NET頁面優化 性能提升8倍的方法
這個頁面其實就是顯示了一堆超鏈接,它們來自于我的博客側邊欄的【推薦排行榜】,總共有20條記錄,我讓頁面重復5次輸出,也就是生成了100個超鏈接。 

測試的數據是這樣獲取的: 
我復制了我的博客側邊欄的【推薦排行榜】的那段HTML代碼,保存到一個文件中: 
ASP.NET頁面優化 性能提升8倍的方法
然后,網站在初始化時,從這段HTML代碼提取鏈接地址以及顯示文字,保存到一個BlogInfo的列表中,代碼如下: 

復制代碼代碼如下:


public class BlogInfo 

public string Title; 
public string Href; 


public static class XmlDb 

public static List<BlogInfo> Blogs { get; private set; } 


public static void LoadBlogs() 

string filePath = Path.Combine(HttpRuntime.AppDomainAppPath, @"App_Data\RecommendList.html"); 

XElement html = XElement.Parse(System.IO.File.ReadAllText(filePath)); 

Blogs = 
(from a in html.Elements("li").Elements("a") 
select new BlogInfo { /> 測試時,就把XmlDb.Blogs的內容顯示在網頁中。 
我想這個測試還是比較接近于現實開發的。 

這里又有一個問題:我如何測試頁面的執行速度? 

雖然說創建HttpWebRequest訪問頁面是個很簡單的方法,但我并不打算這樣做。 
因為從HttpWebRequest發起調用到獲取結果,這其中除了有頁面的執行時間,還混雜較多的額外調用開銷。最終,我選擇了在一次HTTP請求中,循環調用Server.Execute來執行頁面,并統計時間的方式。其實如何選擇測試方法,對于二個測試對象還說,都是公平的。只是說:盡量減少一些額外的調用開銷,會讓測試結果的差異更大,也更明顯。 

說明:為了測試代碼寫起來簡單,我使用了MyMVC框架。 
測試用例1:WebFromPage.aspx 
前面介紹了測試背景以及測試方法。現在就來介紹第1個測試用例,它采用了WebForm編程模型中最經典的寫法。 
頁面代碼: 

復制代碼代碼如下:


<%@ Page Language="C#" CodeFile="WebFromPage.aspx.cs" Inherits="TestPage_WebFromPage" %> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<title>PagePerformanceTest http://www.cnblogs.com/fish-li/</title> 
</head> 
<body> 
<p>This is WebFromPage.aspx</p> 
<asp:Repeater ID="repeater1" runat="server" onitemdatabound="repeater1_ItemDataBound"> 
<ItemTemplate> 
<asp:HyperLink ID="link1" runat="server"></asp:HyperLink><br /> 
</ItemTemplate> 
<FooterTemplate><hr /></FooterTemplate> 
</asp:Repeater> 
<asp:Repeater ID="repeater2" runat="server" onitemdatabound="repeater1_ItemDataBound"> 
<ItemTemplate> 
<asp:HyperLink ID="link1" runat="server"></asp:HyperLink><br /> 
</ItemTemplate> 
<FooterTemplate><hr /></FooterTemplate> 
</asp:Repeater> 
<asp:Repeater ID="repeater3" runat="server" onitemdatabound="repeater1_ItemDataBound"> 
<ItemTemplate> 
<asp:HyperLink ID="link1" runat="server"></asp:HyperLink><br /> 
</ItemTemplate> 
<FooterTemplate><hr /></FooterTemplate> 
</asp:Repeater> 
<asp:Repeater ID="repeater4" runat="server" onitemdatabound="repeater1_ItemDataBound"> 
<ItemTemplate> 
<asp:HyperLink ID="link1" runat="server"></asp:HyperLink><br /> 
</ItemTemplate> 
<FooterTemplate><hr /></FooterTemplate> 
</asp:Repeater> 
<asp:Repeater ID="repeater5" runat="server" onitemdatabound="repeater1_ItemDataBound"> 
<ItemTemplate> 
<asp:HyperLink ID="link1" runat="server"></asp:HyperLink><br /> 
</ItemTemplate> 
<FooterTemplate><hr /></FooterTemplate> 
</asp:Repeater> 

</body> 
</html> 


頁面的CodeFile代碼: 

復制代碼代碼如下:


public partial class TestPage_WebFromPage : System.Web.UI.Page 

protected override void OnLoad(EventArgs e) 

base.OnLoad(e); 
repeater1.DataSource = XmlDb.Blogs; 
repeater1.DataBind(); 
repeater2.DataSource = XmlDb.Blogs; 
repeater2.DataBind(); 
repeater3.DataSource = XmlDb.Blogs; 
repeater3.DataBind(); 
repeater4.DataSource = XmlDb.Blogs; 
repeater4.DataBind(); 
repeater5.DataSource = XmlDb.Blogs; 
repeater5.DataBind(); 

protected void repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e) 

if( e.Item.ItemType == ListItemType.Item ) { 
BlogInfo blog = e.Item.DataItem as BlogInfo; 
HyperLink link1 = e.Item.FindControl("link1") as HyperLink; 
link1.NavigateUrl = blog.Href; 
link1.Text = blog.Title; 



測試代碼: 

復制代碼代碼如下:


[Action] 
public object Test1(string callTimes) 

int count = 0; 
int.TryParse(callTimes, out count); 
if( count <= 0 ) 
return count; 
HttpContext context = HttpContext.Current; 
// 先執行一次,排除編譯時間 
string html = MyMVC.PageExecutor.Render(context, "/TestPage/WebFromPage.aspx", null); 
Stopwatch watch = Stopwatch.StartNew(); 
for( int i = 0; i < count; i++ ) 
html = MyMVC.PageExecutor.Render(context, "/TestPage/WebFromPage.aspx", null); 
watch.Stop(); 
return watch.Elapsed.ToString(); 


當我測試執行10000次時,耗時:00:00:07.5607229 
回到頂部 
測試用例2:InlinePage.aspx 
與測試用例1不同,測試用例2則完全不使用服務器控件。 
頁面代碼: 

復制代碼代碼如下:


<%@ Page Language="C#" %> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<title>PagePerformanceTest http://www.cnblogs.com/fish-li/</title> 
</head> 
<body> 
<p>This is InlinePage.aspx</p> 
<% foreach( BlogInfo b in XmlDb.Blogs ) { %> 
<a href="<%= b.Href %>" target="_blank"><%= b.Title %></a><br /> 
<% } %> 
<hr /> 
<% foreach( BlogInfo b in XmlDb.Blogs ) { %> 
<a href="<%= b.Href %>" target="_blank"><%= b.Title %></a><br /> 
<% } %> 
<hr /> 
<% foreach( BlogInfo b in XmlDb.Blogs ) { %> 
<a href="<%= b.Href %>" target="_blank"><%= b.Title %></a><br /> 
<% } %> 
<hr /> 
<% foreach( BlogInfo b in XmlDb.Blogs ) { %> 
<a href="<%= b.Href %>" target="_blank"><%= b.Title %></a><br /> 
<% } %> 
<hr /> 
<% foreach( BlogInfo b in XmlDb.Blogs ) { %> 
<a href="<%= b.Href %>" target="_blank"><%= b.Title %></a><br /> 
<% } %> 
<hr /> 
</body> 
</html> 


測試代碼: 

復制代碼代碼如下:


[Action] 
public object Test2(string callTimes) 

int count = 0; 
int.TryParse(callTimes, out count); 
if( count <= 0 ) 
return count; 
HttpContext context = HttpContext.Current; 
// 先執行一次,排除編譯時間 
string html = MyMVC.PageExecutor.Render(context, "/TestPage/InlinePage.aspx", null); 
Stopwatch watch = Stopwatch.StartNew(); 
for( int i = 0; i < count; i++ ) 
html = MyMVC.PageExecutor.Render(context, "/TestPage/InlinePage.aspx", null); 
watch.Stop(); 
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時,為了方便編譯網站而寫的一個小工具。 
注意:下載的是一個工具包,安裝后,從開始菜單中運行FishTools\FishAspnetTool即可。 
下面是工具的運行截圖。 
ASP.NET頁面優化 性能提升8倍的方法
操作方法: 
1. 點擊粉色按鈕,選擇網站路徑。 
2. 單選按鈕選擇第2項。 
3. 點擊【發布網站】按鈕。 
在編譯網站之后,我就可以知道網站在運行時如何運行頁面了。 
測試用例1的頁面,最后被編譯成這樣了: 

復制代碼代碼如下:


namespace ASP 

using System; 
using System.Diagnostics; 
using System.Runtime.CompilerServices; 
using System.Web; 
using System.Web.UI; 
using System.Web.UI.WebControls; 
[CompilerGlobalScope] 
public class testpage_webfrompage_aspx : TestPage_WebFromPage, IHttpHandler 

private static object __fileDependencies; 
private static bool __initialized; 
[DebuggerNonUserCode] 
public testpage_webfrompage_aspx() 

base.AppRelativeVirtualPath = "~/TestPage/WebFromPage.aspx"; 
if (!__initialized) 

string[] virtualFileDependencies = new string[] { "~/TestPage/WebFromPage.aspx", "~/TestPage/WebFromPage.aspx.cs" }; 
__fileDependencies = base.GetWrappedFileDependencies(virtualFileDependencies); 
__initialized = true; 

base.Server.ScriptTimeout = 0x1c9c380; 

[DebuggerNonUserCode] 
private void __BuildControl__control10(Control __ctrl) 

IParserAccessor accessor = __ctrl; 
accessor.AddParsedSubObject(new LiteralControl("<hr />")); 

[DebuggerNonUserCode] 
private void __BuildControl__control11(Control __ctrl) 

IParserAccessor accessor = __ctrl; 
accessor.AddParsedSubObject(new LiteralControl("\r\n\t")); 
HyperLink link = this.__BuildControl__control12(); 
accessor.AddParsedSubObject(link); 
accessor.AddParsedSubObject(new LiteralControl("<br />\r\n")); 

[DebuggerNonUserCode] 
private HyperLink __BuildControl__control12() 

HyperLink link = new HyperLink { 
TemplateControl = this 
}; 
link.ApplyStyleSheetSkin(this); 
link.ID = "link1"; 
return link; 

[DebuggerNonUserCode] 
private void __BuildControl__control13(Control __ctrl) 

IParserAccessor accessor = __ctrl; 
accessor.AddParsedSubObject(new LiteralControl("<hr />")); 

[DebuggerNonUserCode] 
private void __BuildControl__control14(Control __ctrl) 

IParserAccessor accessor = __ctrl; 
accessor.AddParsedSubObject(new LiteralControl("\r\n\t")); 
HyperLink link = this.__BuildControl__control15(); 
accessor.AddParsedSubObject(link); 
accessor.AddParsedSubObject(new LiteralControl("<br />\r\n")); 

[DebuggerNonUserCode] 
private HyperLink __BuildControl__control15() 

HyperLink link = new HyperLink { 
TemplateControl = this 
}; 
link.ApplyStyleSheetSkin(this); 
link.ID = "link1"; 
return link; 

[DebuggerNonUserCode] 
private void __BuildControl__control16(Control __ctrl) 

IParserAccessor accessor = __ctrl; 
accessor.AddParsedSubObject(new LiteralControl("<hr />")); 

[DebuggerNonUserCode] 
private void __BuildControl__control2(Control __ctrl) 

IParserAccessor accessor = __ctrl; 
accessor.AddParsedSubObject(new LiteralControl("\r\n\t")); 
HyperLink link = this.__BuildControl__control3(); 
accessor.AddParsedSubObject(link); 
accessor.AddParsedSubObject(new LiteralControl("<br />\r\n")); 

[DebuggerNonUserCode] 
private HyperLink __BuildControl__control3() 

HyperLink link = new HyperLink { 
TemplateControl = this 
}; 
link.ApplyStyleSheetSkin(this); 
link.ID = "link1"; 
return link; 

[DebuggerNonUserCode] 
private void __BuildControl__control4(Control __ctrl) 

IParserAccessor accessor = __ctrl; 
accessor.AddParsedSubObject(new LiteralControl("<hr />")); 

[DebuggerNonUserCode] 
private void __BuildControl__control5(Control __ctrl) 

IParserAccessor accessor = __ctrl; 
accessor.AddParsedSubObject(new LiteralControl("\r\n\t")); 
HyperLink link = this.__BuildControl__control6(); 
accessor.AddParsedSubObject(link); 
accessor.AddParsedSubObject(new LiteralControl("<br />\r\n")); 

[DebuggerNonUserCode] 
private HyperLink __BuildControl__control6() 

HyperLink link = new HyperLink { 
TemplateControl = this 
}; 
link.ApplyStyleSheetSkin(this); 
link.ID = "link1"; 
return link; 

[DebuggerNonUserCode] 
private void __BuildControl__control7(Control __ctrl) 

IParserAccessor accessor = __ctrl; 
accessor.AddParsedSubObject(new LiteralControl("<hr />")); 

[DebuggerNonUserCode] 
private void __BuildControl__control8(Control __ctrl) 

IParserAccessor accessor = __ctrl; 
accessor.AddParsedSubObject(new LiteralControl("\r\n\t")); 
HyperLink link = this.__BuildControl__control9(); 
accessor.AddParsedSubObject(link); 
accessor.AddParsedSubObject(new LiteralControl("<br />\r\n")); 

[DebuggerNonUserCode] 
private HyperLink __BuildControl__control9() 

HyperLink link = new HyperLink { 
TemplateControl = this 
}; 
link.ApplyStyleSheetSkin(this); 
link.ID = "link1"; 
return link; 

[DebuggerNonUserCode] 
private Repeater __BuildControlrepeater1() 

Repeater repeater = new Repeater(); 
base.repeater1 = repeater; 
repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control2)); 
repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control4)); 
repeater.ID = "repeater1"; 
repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound); 
return repeater; 

[DebuggerNonUserCode] 
private Repeater __BuildControlrepeater2() 

Repeater repeater = new Repeater(); 
base.repeater2 = repeater; 
repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control5)); 
repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control7)); 
repeater.ID = "repeater2"; 
repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound); 
return repeater; 

[DebuggerNonUserCode] 
private Repeater __BuildControlrepeater3() 

Repeater repeater = new Repeater(); 
base.repeater3 = repeater; 
repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control8)); 
repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control10)); 
repeater.ID = "repeater3"; 
repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound); 
return repeater; 

[DebuggerNonUserCode] 
private Repeater __BuildControlrepeater4() 

Repeater repeater = new Repeater(); 
base.repeater4 = repeater; 
repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control11)); 
repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control13)); 
repeater.ID = "repeater4"; 
repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound); 
return repeater; 

[DebuggerNonUserCode] 
private Repeater __BuildControlrepeater5() 

Repeater repeater = new Repeater(); 
base.repeater5 = repeater; 
repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control14)); 
repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control16)); 
repeater.ID = "repeater5"; 
repeater.ItemDataBound += new RepeaterItemEventHandler(this.repeater1_ItemDataBound); 
return repeater; 

[DebuggerNonUserCode] 
private void __BuildControlTree(testpage_webfrompage_aspx __ctrl) 

__ctrl.EnableViewState = false; 
__ctrl.EnableViewStateMac = false; 
this.InitializeCulture(); 
IParserAccessor accessor = __ctrl; 
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")); 
Repeater repeater = this.__BuildControlrepeater1(); 
accessor.AddParsedSubObject(repeater); 
accessor.AddParsedSubObject(new LiteralControl("\r\n\r\n")); 
Repeater repeater2 = this.__BuildControlrepeater2(); 
accessor.AddParsedSubObject(repeater2); 
accessor.AddParsedSubObject(new LiteralControl("\r\n\r\n")); 
Repeater repeater3 = this.__BuildControlrepeater3(); 
accessor.AddParsedSubObject(repeater3); 
accessor.AddParsedSubObject(new LiteralControl("\r\n\r\n")); 
Repeater repeater4 = this.__BuildControlrepeater4(); 
accessor.AddParsedSubObject(repeater4); 
accessor.AddParsedSubObject(new LiteralControl("\r\n\r\n")); 
Repeater repeater5 = this.__BuildControlrepeater5(); 
accessor.AddParsedSubObject(repeater5); 
accessor.AddParsedSubObject(new LiteralControl("\r\n\r\n\r\n</body>\r\n</html>\r\n")); 

[DebuggerNonUserCode] 
protected override void FrameworkInitialize() 

base.FrameworkInitialize(); 
this.__BuildControlTree(this); 
base.AddWrappedFileDependencies(__fileDependencies); 
base.Request.ValidateInput(); 

[DebuggerNonUserCode] 
public override int GetTypeHashCode() 

return -781896338; 

[DebuggerNonUserCode] 
public override void ProcessRequest(HttpContext context) 

base.ProcessRequest(context); 

protected override bool SupportAutoEvents 

get 

return false; 




從這個編譯結果我們可以看出:頁面上的所有文字最后也被包裝到LiteralControl中。 
頁面中呈現時,就是循環調用每個控件的Render方法來最終生成HTML結果。 
測試用例2的頁面被編譯成這個樣了: 

復制代碼代碼如下:


namespace ASP 

using System; 
using System.Diagnostics; 
using System.Runtime.CompilerServices; 
using System.Web; 
using System.Web.Profile; 
using System.Web.UI; 
[CompilerGlobalScope] 
public class testpage_inlinepage_aspx : Page, IHttpHandler 

private static object __fileDependencies; 
private static bool __initialized; 
[DebuggerNonUserCode] 
public testpage_inlinepage_aspx() 

base.AppRelativeVirtualPath = "~/TestPage/InlinePage.aspx"; 
if (!__initialized) 

string[] virtualFileDependencies = new string[] { "~/TestPage/InlinePage.aspx" }; 
__fileDependencies = base.GetWrappedFileDependencies(virtualFileDependencies); 
__initialized = true; 

base.Server.ScriptTimeout = 0x1c9c380; 

[DebuggerNonUserCode] 
private void __BuildControlTree(testpage_inlinepage_aspx __ctrl) 

__ctrl.EnableViewState = false; 
__ctrl.EnableViewStateMac = false; 
this.InitializeCulture(); 
__ctrl.SetRenderMethodDelegate(new RenderMethod(this.__Render__control1)); 

private void __Render__control1(HtmlTextWriter __w, Control parameterContainer) 

__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"); 
foreach (BlogInfo info in XmlDb.Blogs) 

__w.Write("\r\n\t<a href=\""); 
__w.Write(info.Href); 
__w.Write("\" target=\"_blank\">"); 
__w.Write(info.Title); 
__w.Write("</a><br />\r\n"); 

__w.Write("\r\n<hr />\r\n\r\n"); 
foreach (BlogInfo info2 in XmlDb.Blogs) 

__w.Write("\r\n\t<a href=\""); 
__w.Write(info2.Href); 
__w.Write("\" target=\"_blank\">"); 
__w.Write(info2.Title); 
__w.Write("</a><br />\r\n"); 

__w.Write("\r\n<hr />\r\n\r\n"); 
foreach (BlogInfo info3 in XmlDb.Blogs) 

__w.Write("\r\n\t<a href=\""); 
__w.Write(info3.Href); 
__w.Write("\" target=\"_blank\">"); 
__w.Write(info3.Title); 
__w.Write("</a><br />\r\n"); 

__w.Write("\r\n<hr />\r\n\r\n"); 
foreach (BlogInfo info4 in XmlDb.Blogs) 

__w.Write("\r\n\t<a href=\""); 
__w.Write(info4.Href); 
__w.Write("\" target=\"_blank\">"); 
__w.Write(info4.Title); 
__w.Write("</a><br />\r\n"); 

__w.Write("\r\n<hr />\r\n\r\n"); 
foreach (BlogInfo info5 in XmlDb.Blogs) 

__w.Write("\r\n\t<a href=\""); 
__w.Write(info5.Href); 
__w.Write("\" target=\"_blank\">"); 
__w.Write(info5.Title); 
__w.Write("</a><br />\r\n"); 

__w.Write("\r\n<hr />\r\n\r\n</body>\r\n</html>\r\n"); 

[DebuggerNonUserCode] 
protected override void FrameworkInitialize() 

base.FrameworkInitialize(); 
this.__BuildControlTree(this); 
base.AddWrappedFileDependencies(__fileDependencies); 
base.Request.ValidateInput(); 

[DebuggerNonUserCode] 
public override int GetTypeHashCode() 

return -1307842476; 

[DebuggerNonUserCode] 
public override void ProcessRequest(HttpContext context) 

base.ProcessRequest(context); 

protected global_asax ApplicationInstance 

get 

return (global_asax) this.Context.ApplicationInstance; 


protected DefaultProfile Profile 

get 

return (DefaultProfile) this.Context.Profile; 


protected override bool SupportAutoEvents 

get 

return false; 




請注意下面這段關鍵的代碼:它們實在太重要了。 

復制代碼代碼如下:


private void __BuildControlTree(testpage_inlinepage_aspx __ctrl) 

// ....... 
__ctrl.SetRenderMethodDelegate(new RenderMethod(this.__Render__control1)); 

private void __Render__control1(HtmlTextWriter __w, Control parameterContainer) 


testpage_inlinepage_aspx與testpage_webfrompage_aspx的編譯結果完全不同。 
最大的差別在testpage_inlinepage_aspx有個方法:__Render__control1 
在這個方法中,頁面的內容將直接被寫入到HtmlTextWriter對象中。 
還有一點我要告訴您:每個Control的輸出最后還是要將自己的顯示代碼寫入到HtmlTextWriter對象中。 
因此,從這里就可以明顯地看出testpage_inlinepage_aspx的執行速度要快很多, 
因為: 
1. 它沒有服務器控件。 
2. 不再需要遞歸循環每個控件,每個控件的生命周期的調用開銷也節省了。 
3. 不用再創建那些服務器控件對象,GC的壓力會小很多。 
4. 輸出方式更高效。 
通過前面的分析,您現在明白了為什么二個頁面的執行速度相差6倍了原因了吧。 
好像還有一點沒有解釋:__Render__control1如何被調用? 
我們都知道:以ASPX頁面為代表的WebForm編程模型在執行時有一個特點:遞歸循環每個控件。 
頁面是在Render階段輸出的,頁面的HTML代碼也是在那個階段輸出到HtmlTextWriter對象中的。 
可是,testpage_inlinepage_aspx沒有任何控件,那又該如何遞歸呢? 
的確,很多書籍以及技術資料都是說:在Render階段會遞歸循環每個控件并調用控件的Render方法。 
其實這種說法是不準確的。Control的Render方法在運行時,會調用下面這個方法: 

復制代碼代碼如下:


internal void RenderChildrenInternal(HtmlTextWriter writer, ICollection children) 

if ((this.RareFields != null) && (this.RareFields.RenderMethod != null)) 

writer.BeginRender(); 
this.RareFields.RenderMethod(writer, this); 
writer.EndRender(); 

else if (children != null) 

foreach (Control control in children) 

control.RenderControl(writer); 



這段代碼中,有個重要的if...else...判斷,簡單說來,就是說要不要調用前面所說的__Render__control1方法。 
從代碼可以看出,如果是進入了if語句塊,則不用遞歸循環每個控件并調用控件的Render方法。 
那么如何能進入if語句塊呢? 
答案是:調用Control.SetRenderMethodDelegate方法。 
testpage_inlinepage_aspx的編譯生成代碼中就有這個調用。 
對于這個方法,MSDN的解釋很含糊: 
此 API 支持 .NET Framework 基礎結構,不適合在代碼中直接使用。 
分配事件處理程序委托,以將服務器控件及其內容呈現到父控件中。 
回到頂部 
測試用例3:InlineUserControl.ascx 
在測試用例3中,我將頁面中用于輸出的代碼移到一個用戶控件中。 
用戶控件的代碼此處省略,與測試用例2的代碼基本上一致。編譯后的結果也基本差不多。 
測試代碼: 

復制代碼代碼如下:


[Action] 
public object Test3(string callTimes) 

int count = 0; 
int.TryParse(callTimes, out count); 
if( count <= 0 ) 
return count; 
// 先執行一次,排除編譯時間 
string html = MyMVC.UcExecutor.Render("/UserControl/InlineUserControl.ascx", null); 
Stopwatch watch = Stopwatch.StartNew(); 
for( int i = 0; i < count; i++ ) 
html = MyMVC.UcExecutor.Render("/UserControl/InlineUserControl.ascx", null); 
watch.Stop(); 
return watch.Elapsed.ToString(); 


當我測試執行10000次時,耗時:00:00:00.9132738 
又快了一點。 
說明:為了這次的性能優化,MyMVC框架也做了一點調整。如果您以前下載過這個框架,請重新下載。 
回到頂部 
分析優化結果2 
經過前面的分析,我們知道:不創建服務器控件對象以及不調用它們的生命周期,可以讓頁面的執行速度快很多。 
有沒有再想像一下:頁面也有生命周期啊,而且生命周期的步驟更長,省略它,會不會更快呢? 
不過,Render方法并不是個public方法,我們還不能直接調用,但可以調用RenderControl方法來實現這一過程。 
由于跳過頁面的生命周期,任何服務器控件都不能使用了,包括母板頁。所以我選擇將前面測試用的那段代碼移到用戶控件中,然后將用戶控件加載到Page中來測試。 
測試用例3與測試用例2相比,在測試過程中,由于跳過了頁面的生命周期,因此速度也就更快了。 
嗯,基本上,就是這個簡單的原因吧。 
由于這種方法沒有任何的控件生命周期,因此速度是最快的。 
經過這一系列的優化,頁面的執行時間最終由 00:00:07.5607229 減少到 00:00:00.9132738 

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久91精品国产91久 | 国产悠悠视频在线播放 | 99精品全国免费7观看视频 | 精品蜜臀AV在线天堂 | 国产亚洲综合成人91精品 | 精品一区heyzo在线播放 | 动漫白丝袜美女羞羞 | 男生和老师一起差差差 | 国产91精品在线播放 | 亚洲大爷操 | 日本高清在线精品一区二区三区 | 精品日韩视频 | 国产香蕉在线视频 | 91伊人网 | 国产成人h综合亚洲欧美在线 | 无码AV精品一区二区三区 | 日本剧情片在线播放中文版 | 干美女在线视频 | 色综合中文字幕在线亚洲 | 日本国产一区二区三区 | 欧美另类老女人 | 91精品综合 | 亚洲欧洲淘宝天堂日本 | 四虎影视免费观看免费观看 | 粉嫩极品国产在线观看免费 | 扒开女人下面 | 美女福利视频网站 | 操mm| 天天亚洲综合 | 精品国产福利一区二区在线 | 秋葵丝瓜茄子草莓榴莲樱桃 | 暴露狂婷婷 | 男女啪啪gif| 99精品国产成人a∨免费看 | bbbxxx乱大交欧美小说 | 国产经典一区 | 女人张开腿 让男人桶个爽 免费观看 | 任你操视频在线观看 | 久久精品123 | 国产91精选学生在线观看 | 久久精品免视看国产 |