• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
    問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
    當前位置: 首頁 - 科技 - 知識百科 - 正文

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

    來源:懂視網 責編:小采 時間:2020-11-27 22:42:26
    文檔

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

    ASP.NET頁面優化 性能提升8倍的方法:為了讓您對優化的效果有個直觀的了解,我準備了下面的測試結果截圖: 測試環境: 1. Windows Server 2003 SP2 2. Viaual Studio 2008,使用自帶的WebDev.WebServer.EXE運行網站程序。 3. (ThinkPad SL510):Core2 T6670 2
    推薦度:
    導讀ASP.NET頁面優化 性能提升8倍的方法:為了讓您對優化的效果有個直觀的了解,我準備了下面的測試結果截圖: 測試環境: 1. Windows Server 2003 SP2 2. Viaual Studio 2008,使用自帶的WebDev.WebServer.EXE運行網站程序。 3. (ThinkPad SL510):Core2 T6670 2

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

    測試環境:
    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服務器控件的使用,測試結果也僅僅只是一個參考數字。
    如果您認為您的開發工作非常依賴于服務器控件的使用,
    那么測試結果對您來說其實是無意義的,請不要在意這個結果。
    測試方法
    在這次優化過程中,我并沒有設計很復雜的測試頁面,而是一個很簡單的測試頁面,頁面顯示效果如下:

    這個頁面其實就是顯示了一堆超鏈接,它們來自于我的博客側邊欄的【推薦排行榜】,總共有20條記錄,我讓頁面重復5次輸出,也就是生成了100個超鏈接。

    測試的數據是這樣獲取的:
    我復制了我的博客側邊欄的【推薦排行榜】的那段HTML代碼,保存到一個文件中:

    然后,網站在初始化時,從這段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 { Title = a.Value, Href = a.Attribute("href").Value }).ToList();
    }
    }

    測試時,就把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時,為了方便編譯網站而寫的一個小工具。
    下載地址://www.gxlcms.com/article/29875.htm
    注意:下載的是一個工具包,安裝后,從開始菜單中運行FishTools\FishAspnetTool即可。
    下面是工具的運行截圖。

    操作方法:
    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

    點擊此處下載示例代碼

    聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

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

    ASP.NET頁面優化 性能提升8倍的方法:為了讓您對優化的效果有個直觀的了解,我準備了下面的測試結果截圖: 測試環境: 1. Windows Server 2003 SP2 2. Viaual Studio 2008,使用自帶的WebDev.WebServer.EXE運行網站程序。 3. (ThinkPad SL510):Core2 T6670 2
    推薦度:
    標簽: 提升 頁面 的方法
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 老司机午夜网站国内精品久久久久久久久| 国产精品91在线| 国产精品福利片免费看 | www夜片内射视频日韩精品成人| 国产精品视频第一页| 欧美韩国精品另类综合| 精品国产污污免费网站入口在线| 欧美激情精品久久久久久| 青青草原精品国产亚洲av| 国产一区二区精品久久| 久久精品国产亚洲7777| 久久99精品久久久久子伦| 久久国产精品国产自线拍免费| 一本久久a久久精品综合夜夜| 精品精品国产理论在线观看| 亚洲AV无码国产精品麻豆天美| 久久er国产精品免费观看2| 久久久久久极精品久久久 | 久久久精品人妻一区二区三区蜜桃 | 区亚洲欧美一级久久精品亚洲精品成人网久久久久 | 亚洲?V无码乱码国产精品| 国产成人精品日本亚洲直接 | 国产精品久久久久久搜索| 国产AV国片精品有毛| 国产精品.XX视频.XXTV| 996久久国产精品线观看| 国产精品 91 第一页| 成人精品视频一区二区三区| 无码精品第一页| 久久国产精品二国产精品| 2021久久国自产拍精品| 久久福利青草精品资源站免费 | 国产高清在线精品一区二区| 日本午夜精品一区二区三区电影| 国产精品久久久99| 国产精品日韩深夜福利久久| 亚洲精品无码成人片在线观看| 999精品在线| 最新国产精品亚洲| 免费精品久久久久久中文字幕 | 国产精品毛片a∨一区二区三区|