亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

ASP.NET頁面優化性能提升方法記錄

2019-11-14 16:34:23
字體:
來源:轉載
供稿:網友

今天與大家分享:一種優化頁面執行速度的方法。
采用這個方法,可以使用頁面的執行速度獲得【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這類簡單的服務器控件?;蛟S有些人認為:我已不使用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.49028c.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.49028c.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。 

在編譯網站之后,我就可以知道網站在運行時如何運行頁面了。

測試用例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.49028c.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.49028c.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

再次申明:測試結果也僅僅只是一個參考數字。
事實上,使用服務器控件產生的對象涉及到GC的回收以及內存占用的影響也是不可忽視的。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
在线亚洲午夜片av大片| 亚洲国产精品嫩草影院久久| 久久视频在线免费观看| 国产一区二区av| 国产精品情侣自拍| 91av在线播放| 亚洲日本中文字幕| 亚洲成人av在线播放| 欧美丰满老妇厨房牲生活| 亚洲美女自拍视频| 日韩女优人人人人射在线视频| 隔壁老王国产在线精品| 北条麻妃在线一区二区| 欧美交受高潮1| 日本精品视频在线观看| 日韩av成人在线| 91免费人成网站在线观看18| 亚洲在线一区二区| 4p变态网欧美系列| 欧美韩国理论所午夜片917电影| 91在线观看欧美日韩| 91欧美精品午夜性色福利在线| 夜色77av精品影院| 在线亚洲男人天堂| 黑人巨大精品欧美一区二区| 精品无人区太爽高潮在线播放| 欧美成人h版在线观看| 欧美一级大片视频| 久久久精品国产一区二区| 亚洲激情免费观看| 亚洲人成啪啪网站| 美女福利视频一区| 国产精品视频久久久久| 中文字幕在线观看日韩| 欧美日韩亚洲精品内裤| 97福利一区二区| 国产亚洲福利一区| 精品久久久香蕉免费精品视频| 久久男人av资源网站| 一区二区日韩精品| 色综合天天综合网国产成人网| 色婷婷综合久久久久中文字幕1| 成人看片人aa| 在线观看不卡av| 97超碰蝌蚪网人人做人人爽| 亚洲性视频网址| 欧美日韩亚洲成人| 国产精品精品视频| 亚洲久久久久久久久久久| 亚洲国产精品一区二区三区| 欧美精品久久久久| 成人写真视频福利网| 日韩经典一区二区三区| 一区二区欧美日韩视频| xvideos成人免费中文版| 最近2019年手机中文字幕| 国产精品一区久久| 中文字幕av一区二区三区谷原希美| 欧美性生交大片免费| 岛国av一区二区在线在线观看| 日韩成人中文字幕| 91av在线播放视频| 日韩视频免费大全中文字幕| 日韩免费在线观看视频| 日本成熟性欧美| 97超级碰碰碰| 亚洲精品理论电影| 亚洲视频网站在线观看| 国产91精品久久久久久久| 精品动漫一区二区| 国产精品www| 亚洲国产精品高清久久久| 欧美日韩国产一区二区| 亚洲欧美精品一区二区| 韩国一区二区电影| 狠狠躁夜夜躁人人爽天天天天97| 国产成人综合av| 国产区亚洲区欧美区| 国产精品一区二区久久国产| 亚洲国产精品一区二区久| 亚洲精品一区久久久久久| 欧美精品一区在线播放| 亚洲女在线观看| 日韩av电影国产| 久久伊人免费视频| 国产在线观看精品一区二区三区| 97热在线精品视频在线观看| 亚洲电影天堂av| 欧美丰满少妇xxxx| 国产精品久久久久av| 欧美富婆性猛交| 久久久久久69| 亚洲欧美日韩精品久久| 欧美激情视频三区| 免费99精品国产自在在线| 日本精品久久久久久久| 欧美激情videoshd| 亚洲日本欧美日韩高观看| 日韩精品欧美激情| 国产精品高清免费在线观看| 91福利视频在线观看| 秋霞午夜一区二区| 亚洲视频在线播放| 亚洲第一偷拍网| 大伊人狠狠躁夜夜躁av一区| 成人国内精品久久久久一区| 欧洲s码亚洲m码精品一区| 久久久久久亚洲精品| 久久精品国产一区| 欧美电影在线观看高清| 国产日产久久高清欧美一区| 亚洲一区二区三区sesese| 国产精品网红直播| 日本一本a高清免费不卡| 亚洲人成在线观看网站高清| 久久久久久久97| 国产乱人伦真实精品视频| 中文字幕av一区二区| 亚洲国产日韩欧美在线99| 欧美亚洲视频在线看网址| 亚洲国产99精品国自产| 久久视频国产精品免费视频在线| 久久精品这里热有精品| 日本免费久久高清视频| 日韩久久精品电影| 精品久久久久久| 欧美福利在线观看| 欧美一乱一性一交一视频| 中文国产成人精品久久一| 国产成人精品免高潮费视频| 91麻豆国产语对白在线观看| 欧美性生交大片免费| 精品久久中文字幕| 久久久电影免费观看完整版| 中文字幕欧美精品日韩中文字幕| 欧美多人爱爱视频网站| 久久精品国产综合| 欧美成人剧情片在线观看| 最近日韩中文字幕中文| www国产91| 精品福利免费观看| 中文字幕一精品亚洲无线一区| 日韩成人在线电影网| 亚洲乱码av中文一区二区| 欧美高清视频一区二区| 亚洲欧美在线x视频| 亚洲а∨天堂久久精品9966| 久久精品国产欧美激情| 2019亚洲男人天堂| 精品电影在线观看| 亚洲精品不卡在线| 亚洲国产另类 国产精品国产免费| 一区二区三区精品99久久| 亚洲一区二区黄| 91精品国产91久久久久久不卡| 亚洲欧洲偷拍精品| 国产精品电影网| 人九九综合九九宗合| 国产精品久久久91| 亚洲xxxxx性| 国语自产偷拍精品视频偷| 青青草成人在线| 一区二区三区天堂av| 国产精品电影久久久久电影网|