国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

ASP.NET頁(yè)面優(yōu)化性能提升方法記錄

2019-11-14 16:34:23
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

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

為了讓您對(duì)優(yōu)化的效果有個(gè)直觀(guān)的了解,我準(zhǔn)備了下面的測(cè)試結(jié)果截圖:

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

二個(gè)紅框中的數(shù)字反映了優(yōu)化前后的執(zhí)行時(shí)間。
數(shù)字表明:優(yōu)化前后,執(zhí)行時(shí)間有了8倍多的差別。

本文的測(cè)試結(jié)果也僅僅只是一個(gè)參考數(shù)字,這個(gè)結(jié)果也只是根據(jù)我所設(shè)計(jì)的測(cè)試頁(yè)面得出的。
優(yōu)化的過(guò)程中,如果不使用服務(wù)器控件,那么給GC減少的壓力其實(shí)也是無(wú)法測(cè)試到的。
在測(cè)試過(guò)程中,我還發(fā)現(xiàn)測(cè)試結(jié)果并不是很穩(wěn)定,因此截圖具有一定的偶然性。
測(cè)試頁(yè)面或許在某些方面存在一些片面性,因此,結(jié)果僅供參考。

回到頂部

測(cè)試背景

看過(guò)了優(yōu)化結(jié)果,再來(lái)介紹一下:這個(gè)測(cè)試到底是在測(cè)試什么東西?

現(xiàn)在有很多做asp.net的開(kāi)發(fā)人員,應(yīng)該都是從ASP.NET的WebForm編程模型開(kāi)始學(xué)習(xí)的。大家都很喜歡用服務(wù)器控件,不管輸出什么,都會(huì)使用服務(wù)器控件。有時(shí)候?yàn)榱俗岉?yè)面呈現(xiàn)干凈的HTML代碼,有些人會(huì)選擇使用Repeater,Literal這類(lèi)簡(jiǎn)單的服務(wù)器控件?;蛟S有些人認(rèn)為:我已不使用GridView這樣強(qiáng)大復(fù)雜的控件,頁(yè)面執(zhí)行速度已經(jīng)很快了。

真是這樣嗎?

今天測(cè)試的起點(diǎn)就從使用簡(jiǎn)單的服務(wù)器開(kāi)始,我會(huì)分二次對(duì)它做一系列的性能優(yōu)化。
最終就是上圖中的3個(gè)結(jié)果,它們反映了二次優(yōu)化的改進(jìn)過(guò)程。

 

在繼續(xù)介紹之前,有一點(diǎn)我想有必要說(shuō)明一下:

優(yōu)化的過(guò)程涉及到ASP.NET服務(wù)器控件的使用,測(cè)試結(jié)果也僅僅只是一個(gè)參考數(shù)字。
如果您認(rèn)為您的開(kāi)發(fā)工作非常依賴(lài)于服務(wù)器控件的使用,
那么測(cè)試結(jié)果對(duì)您來(lái)說(shuō)其實(shí)是無(wú)意義的,請(qǐng)不要在意這個(gè)結(jié)果。

回到頂部

測(cè)試方法

在這次優(yōu)化過(guò)程中,我并沒(méi)有設(shè)計(jì)很復(fù)雜的測(cè)試頁(yè)面,而是一個(gè)很簡(jiǎn)單的測(cè)試頁(yè)面,頁(yè)面顯示效果如下:

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

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

然后,網(wǎng)站在初始化時(shí),從這段HTML代碼提取鏈接地址以及顯示文字,保存到一個(gè)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();    }}

測(cè)試時(shí),就把XmlDb.Blogs的內(nèi)容顯示在網(wǎng)頁(yè)中。
我想這個(gè)測(cè)試還是比較接近于現(xiàn)實(shí)開(kāi)發(fā)的。

這里又有一個(gè)問(wèn)題:我如何測(cè)試頁(yè)面的執(zhí)行速度?

雖然說(shuō)創(chuàng)建HttpWebRequest訪(fǎng)問(wèn)頁(yè)面是個(gè)很簡(jiǎn)單的方法,但我并不打算這樣做。
因?yàn)閺腍ttpWebRequest發(fā)起調(diào)用到獲取結(jié)果,這其中除了有頁(yè)面的執(zhí)行時(shí)間,還混雜較多的額外調(diào)用開(kāi)銷(xiāo)。最終,我選擇了在一次HTTP請(qǐng)求中,循環(huán)調(diào)用Server.Execute來(lái)執(zhí)行頁(yè)面,并統(tǒng)計(jì)時(shí)間的方式。其實(shí)如何選擇測(cè)試方法,對(duì)于二個(gè)測(cè)試對(duì)象還說(shuō),都是公平的。只是說(shuō):盡量減少一些額外的調(diào)用開(kāi)銷(xiāo),會(huì)讓測(cè)試結(jié)果的差異更大,也更明顯。

說(shuō)明:為了測(cè)試代碼寫(xiě)起來(lái)簡(jiǎn)單,我使用了MyMVC框架。

回到頂部

測(cè)試用例1:WebFromPage.aspx

前面介紹了測(cè)試背景以及測(cè)試方法?,F(xiàn)在就來(lái)介紹第1個(gè)測(cè)試用例,它采用了WebForm編程模型中最經(jīng)典的寫(xiě)法。

頁(yè)面代碼: 

<%@ Page Language="C#" CodeFile="WebFromPage.aspx.cs" Inherits="TestPage_WebFromPage" %><html xmlns="http://www.w3.org/1999/xhtml"><head>    <title>PagePerformanceTest   http://m.survivalescaperooms.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>

頁(yè)面的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;        }    }}

測(cè)試代碼: 

[Action]public object Test1(string callTimes){    int count = 0;    int.TryParse(callTimes, out count);    if( count <= 0 )        return count;    HttpContext context = HttpContext.Current;        // 先執(zhí)行一次,排除編譯時(shí)間    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();}

當(dāng)我測(cè)試執(zhí)行10000次時(shí),耗時(shí):00:00:07.5607229

回到頂部

測(cè)試用例2:InlinePage.aspx

與測(cè)試用例1不同,測(cè)試用例2則完全不使用服務(wù)器控件。

頁(yè)面代碼: 

<%@ Page Language="C#" %><html xmlns="http://www.w3.org/1999/xhtml"><head>    <title>PagePerformanceTest   http://m.survivalescaperooms.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>

測(cè)試代碼: 

[Action]public object Test2(string callTimes){    int count = 0;    int.TryParse(callTimes, out count);    if( count <= 0 )        return count;    HttpContext context = HttpContext.Current;    // 先執(zhí)行一次,排除編譯時(shí)間    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();}

當(dāng)我測(cè)試執(zhí)行10000次時(shí),耗時(shí):00:00:01.2345842

回到頂部

分析優(yōu)化結(jié)果1

測(cè)試用例1執(zhí)行相同次數(shù)所花費(fèi)的時(shí)間是測(cè)試用例2的6倍,為什么會(huì)這樣呢?

為了回答這個(gè)問(wèn)題,我們首先要知道前面二個(gè)頁(yè)面在執(zhí)行時(shí),它們是如何運(yùn)行的。
說(shuō)到這里,就不得不談ASP.NET的頁(yè)面編譯方式了。

ASP.NET的頁(yè)面編譯過(guò)程是個(gè)復(fù)雜的操作,其實(shí)我們可以不用關(guān)心頁(yè)面是如何編譯的,
但要知道:頁(yè)面編譯后是什么樣的。

為了能直觀(guān)地了解頁(yè)面編譯后的樣子,我編譯了整個(gè)網(wǎng)站,并生成到一個(gè)DLL文件中,然后使用Reflector.exe來(lái)分析這個(gè)DLL的源代碼。

將網(wǎng)站編譯成一個(gè)DLL文件有二個(gè)方法:
1. 安裝WebDeployment插件。
2. 使用我的工具:FishAspnetTool。 

在編譯網(wǎng)站之后,我就可以知道網(wǎng)站在運(yùn)行時(shí)如何運(yùn)行頁(yè)面了。

測(cè)試用例1的頁(yè)面,最后被編譯成這樣了: 

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://m.survivalescaperooms.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;            }        }    }}

從這個(gè)編譯結(jié)果我們可以看出:頁(yè)面上的所有文字最后也被包裝到LiteralControl中。
頁(yè)面中呈現(xiàn)時(shí),就是循環(huán)調(diào)用每個(gè)控件的Render方法來(lái)最終生成HTML結(jié)果。

測(cè)試用例2的頁(yè)面被編譯成這個(gè)樣了: 

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://m.survivalescaperooms.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;            }        }    }}

請(qǐng)注意下面這段關(guān)鍵的代碼:它們實(shí)在太重要了。

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的編譯結(jié)果完全不同。
最大的差別在testpage_inlinepage_aspx有個(gè)方法:__Render__control1
在這個(gè)方法中,頁(yè)面的內(nèi)容將直接被寫(xiě)入到HtmlTextWriter對(duì)象中。
還有一點(diǎn)我要告訴您:每個(gè)Control的輸出最后還是要將自己的顯示代碼寫(xiě)入到HtmlTextWriter對(duì)象中。
因此,從這里就可以明顯地看出testpage_inlinepage_aspx的執(zhí)行速度要快很多,
因?yàn)椋?br />1. 它沒(méi)有服務(wù)器控件。
2. 不再需要遞歸循環(huán)每個(gè)控件,每個(gè)控件的生命周期的調(diào)用開(kāi)銷(xiāo)也節(jié)省了。
3. 不用再創(chuàng)建那些服務(wù)器控件對(duì)象,GC的壓力會(huì)小很多。
4. 輸出方式更高效。

通過(guò)前面的分析,您現(xiàn)在明白了為什么二個(gè)頁(yè)面的執(zhí)行速度相差6倍了原因了吧。

好像還有一點(diǎn)沒(méi)有解釋?zhuān)?strong class="redText">__Render__control1如何被調(diào)用?

我們都知道:以ASPX頁(yè)面為代表的WebForm編程模型在執(zhí)行時(shí)有一個(gè)特點(diǎn):遞歸循環(huán)每個(gè)控件。
頁(yè)面是在Render階段輸出的,頁(yè)面的HTML代碼也是在那個(gè)階段輸出到HtmlTextWriter對(duì)象中的。
可是,testpage_inlinepage_aspx沒(méi)有任何控件,那又該如何遞歸呢?

的確,很多書(shū)籍以及技術(shù)資料都是說(shuō):在Render階段會(huì)遞歸循環(huán)每個(gè)控件并調(diào)用控件的Render方法。

其實(shí)這種說(shuō)法是不準(zhǔn)確的。Control的Render方法在運(yùn)行時(shí),會(huì)調(diào)用下面這個(gè)方法: 

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);        }    }}

這段代碼中,有個(gè)重要的if...else...判斷,簡(jiǎn)單說(shuō)來(lái),就是說(shuō)要不要調(diào)用前面所說(shuō)的__Render__control1方法。
從代碼可以看出,如果是進(jìn)入了if語(yǔ)句塊,則不用遞歸循環(huán)每個(gè)控件并調(diào)用控件的Render方法。

那么如何能進(jìn)入if語(yǔ)句塊呢?
答案是:調(diào)用Control.SetRenderMethodDelegate方法。
testpage_inlinepage_aspx的編譯生成代碼中就有這個(gè)調(diào)用。
對(duì)于這個(gè)方法,MSDN的解釋很含糊:

此 API 支持 .NET Framework 基礎(chǔ)結(jié)構(gòu),不適合在代碼中直接使用。 

分配事件處理程序委托,以將服務(wù)器控件及其內(nèi)容呈現(xiàn)到父控件中。

回到頂部

測(cè)試用例3:InlineUserControl.ascx

在測(cè)試用例3中,我將頁(yè)面中用于輸出的代碼移到一個(gè)用戶(hù)控件中。
用戶(hù)控件的代碼此處省略,與測(cè)試用例2的代碼基本上一致。編譯后的結(jié)果也基本差不多。

測(cè)試代碼: 

[Action]public object Test3(string callTimes){    int count = 0;    int.TryParse(callTimes, out count);    if( count <= 0 )        return count;    // 先執(zhí)行一次,排除編譯時(shí)間    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();}

當(dāng)我測(cè)試執(zhí)行10000次時(shí),耗時(shí):00:00:00.9132738

又快了一點(diǎn)。

說(shuō)明:為了這次的性能優(yōu)化,MyMVC框架也做了一點(diǎn)調(diào)整。如果您以前下載過(guò)這個(gè)框架,請(qǐng)重新下載。

回到頂部

分析優(yōu)化結(jié)果2

經(jīng)過(guò)前面的分析,我們知道:不創(chuàng)建服務(wù)器控件對(duì)象以及不調(diào)用它們的生命周期,可以讓頁(yè)面的執(zhí)行速度快很多。

有沒(méi)有再想像一下:頁(yè)面也有生命周期啊,而且生命周期的步驟更長(zhǎng),省略它,會(huì)不會(huì)更快呢?

不過(guò),Render方法并不是個(gè)public方法,我們還不能直接調(diào)用,但可以調(diào)用RenderControl方法來(lái)實(shí)現(xiàn)這一過(guò)程。

由于跳過(guò)頁(yè)面的生命周期,任何服務(wù)器控件都不能使用了,包括母板頁(yè)。所以我選擇將前面測(cè)試用的那段代碼移到用戶(hù)控件中,然后將用戶(hù)控件加載到Page中來(lái)測(cè)試。

測(cè)試用例3與測(cè)試用例2相比,在測(cè)試過(guò)程中,由于跳過(guò)了頁(yè)面的生命周期,因此速度也就更快了。
注意:事實(shí)上,動(dòng)態(tài)加載用戶(hù)控件也會(huì)有一定的調(diào)用開(kāi)銷(xiāo)。這種方法也僅供參考,可以根據(jù)實(shí)際情況來(lái)選擇。

嗯,基本上,就是這個(gè)簡(jiǎn)單的原因吧。

由于這種方法沒(méi)有任何的控件生命周期,因此速度是最快的。

經(jīng)過(guò)這一系列的優(yōu)化,頁(yè)面的執(zhí)行時(shí)間最終由 00:00:07.5607229 減少到 00:00:00.9132738

再次申明:測(cè)試結(jié)果也僅僅只是一個(gè)參考數(shù)字。
事實(shí)上,使用服務(wù)器控件產(chǎn)生的對(duì)象涉及到GC的回收以及內(nèi)存占用的影響也是不可忽視的。


發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 绍兴市| 专栏| 四平市| 温泉县| 玛纳斯县| 邻水| 巨鹿县| 普宁市| 和顺县| 广水市| 青田县| 巴彦县| 洪泽县| 宁海县| 江永县| 南通市| 清苑县| 碌曲县| 东乡族自治县| 博乐市| 无棣县| 辉南县| 连南| 应城市| SHOW| 明水县| 华阴市| 崇明县| 鸡西市| 日照市| 瓮安县| 顺义区| 昔阳县| 丹寨县| 岳西县| 临洮县| 庆城县| 洛宁县| 金溪县| 宁强县| 彭州市|