ASP.NET 페이지 최적화 성능 8 배 향상 방법

최적화 효과 에 대해 직관 적 으로 이해 할 수 있 도록 다음 테스트 결 과 를 캡 처 했 습 니 다.
테스트 환경:1.Windows Server 2003 SP2 2 2.Viaual Studio 2008,자체 웹 Dev.WebServer.EXE 를 사용 하여 웹 프로그램 을 실행 합 니 다.3.(ThinkPad SL 510):Core 2 T6670 2.2GHz,4G 메모리 두 개의 빨 간 상자 에 있 는 숫자 는 최적화 전후의 실행 시간 을 반영 합 니 다.숫자 에 따 르 면 최적화 전후 에 집행 시간 은 8 배 이상 차이 가 났 다.테스트 배경 에서 최적화 결 과 를 보 았 습 니 다.다시 한 번 소개 하 겠 습 니 다.이 테스트 는 도대체 무엇 을 테스트 하 는 것 입 니까?현재 ASP.NET 을 만 드 는 개발 자 들 이 많 습 니 다.NET 의 WebForm 프로 그래 밍 모델 부터 배 웠 을 겁 니 다.서버 컨트롤 을 사용 하 는 것 을 좋아 합 니 다.무엇 을 출력 하 든 서버 컨트롤 을 사용 합 니 다.페이지 가 깨끗 한 HTML 코드 를 보 여주 기 위해 Repeater,Literal 같은 간단 한 서버 컨트롤 을 선택 하 는 경우 도 있다.아마도 어떤 사람들 은 내 가 GridView 와 같은 강력 하고 복잡 한 컨트롤 을 사용 하지 않 아서 페이지 의 실행 속도 가 이미 매우 빠르다 고 생각 할 것 이다.정말 그렇습니까?오늘 테스트 의 출발점 은 간단 한 서버 를 사용 하 는 것 부터 시작 해서 나 는 두 번 으로 나 누 어 그것 에 대해 일련의 성능 최 적 화 를 할 것 이다.마지막 으로 위의 그림 에서 세 가지 결 과 는 2 차 최적화 의 개선 과정 을 나 타 냈 다.계속 소개 하기 전에 한 가지 설명 이 필요 합 니 다.최적화 과정 은 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.Blags 의 내용 을 표시 합 니 다.나 는 이 테스트 가 여전히 현실 개발 에 비교적 가깝다 고 생각한다.여기에 또 하나의 문제 가 있다.나 는 어떻게 페이지 의 실행 속 도 를 테스트 합 니까?HttpWebRequest 방문 페이지 를 만 드 는 것 은 간단 한 방법 이 라 고 하지만 그 럴 생각 은 없습니다.HttpWebRequest 에서 결 과 를 가 져 오기 위해 호출 되 었 기 때문에 페이지 의 실행 시간 외 에 도 추가 호출 비용 이 많이 섞 여 있 습 니 다.결국,나 는 HTTP 요청 에서 서버.Execute 를 반복 해서 호출 하여 페이지 를 실행 하고 시간 을 집계 하 는 방식 을 선택 했다.사실 어떻게 테스트 방법 을 선택 하 는 지 는 두 테스트 대상 에 게 모두 공평 하 다 고 말한다.다만 추가 호출 비용 을 최소 화하 면 테스트 결과 의 차이 가 더 크 고 뚜렷 하 다 고 말 했다.설명:테스트 코드 를 간단하게 쓰기 위해 MyMVC 프레임 워 크 를 사 용 했 습 니 다.테스트 용례 1:WebFromPage.aspx 앞에서 테스트 배경 과 테스트 방법 을 소개 했다.이제 첫 번 째 테스트 사례 를 소개 하 겠 습 니 다.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 를 사용 할 때 웹 사 이 트 를 편리 하 게 컴 파일 하기 위해 쓴 작은 도구 입 니 다.다운로드 주소:https://www.jb51.net/article/29875.htm주의:다운로드 한 것 은 공구 꾸러미 입 니 다.설치 후 시작 메뉴 에서 FishTools\FishAspnetTool 을 실행 하면 됩 니 다.다음은 도구 의 실행 캡 처 입 니 다.조작 방법:1.분홍색 단 추 를 누 르 고 사이트 경 로 를 선택한다.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
\t"));
HyperLink link = this.__BuildControl__control12();
accessor.AddParsedSubObject(link);
accessor.AddParsedSubObject(new LiteralControl("<br />\r
"));
}
[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
\t"));
HyperLink link = this.__BuildControl__control15();
accessor.AddParsedSubObject(link);
accessor.AddParsedSubObject(new LiteralControl("<br />\r
"));
}
[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
\t"));
HyperLink link = this.__BuildControl__control3();
accessor.AddParsedSubObject(link);
accessor.AddParsedSubObject(new LiteralControl("<br />\r
"));
}
[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
\t"));
HyperLink link = this.__BuildControl__control6();
accessor.AddParsedSubObject(link);
accessor.AddParsedSubObject(new LiteralControl("<br />\r
"));
}
[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
\t"));
HyperLink link = this.__BuildControl__control9();
accessor.AddParsedSubObject(link);
accessor.AddParsedSubObject(new LiteralControl("<br />\r
"));
}
[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
\r
<html xmlns=\"http://www.w3.org/1999/xhtml\">\r
<head>\r
<title>PagePerformanceTest http://www.cnblogs.com/fish-li/</title>\r
</head>\r
<body>\r
\r
<p>This is WebFromPage.aspx</p>\r
\r
"));
Repeater repeater = this.__BuildControlrepeater1();
accessor.AddParsedSubObject(repeater);
accessor.AddParsedSubObject(new LiteralControl("\r
\r
"));
Repeater repeater2 = this.__BuildControlrepeater2();
accessor.AddParsedSubObject(repeater2);
accessor.AddParsedSubObject(new LiteralControl("\r
\r
"));
Repeater repeater3 = this.__BuildControlrepeater3();
accessor.AddParsedSubObject(repeater3);
accessor.AddParsedSubObject(new LiteralControl("\r
\r
"));
Repeater repeater4 = this.__BuildControlrepeater4();
accessor.AddParsedSubObject(repeater4);
accessor.AddParsedSubObject(new LiteralControl("\r
\r
"));
Repeater repeater5 = this.__BuildControlrepeater5();
accessor.AddParsedSubObject(repeater5);
accessor.AddParsedSubObject(new LiteralControl("\r
\r
\r
</body>\r
</html>\r
"));
}
[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
\r
<html xmlns=\"http://www.w3.org/1999/xhtml\">\r
<head>\r
<title>PagePerformanceTest http://www.cnblogs.com/fish-li/</title>\r
</head>\r
<body>\r
\r
<p>This is InlinePage.aspx</p>\r
\r
");
foreach (BlogInfo info in XmlDb.Blogs)
{
__w.Write("\r
\t<a href=\"");
__w.Write(info.Href);
__w.Write("\" target=\"_blank\">");
__w.Write(info.Title);
__w.Write("</a><br />\r
");
}
__w.Write("\r
<hr />\r
\r
");
foreach (BlogInfo info2 in XmlDb.Blogs)
{
__w.Write("\r
\t<a href=\"");
__w.Write(info2.Href);
__w.Write("\" target=\"_blank\">");
__w.Write(info2.Title);
__w.Write("</a><br />\r
");
}
__w.Write("\r
<hr />\r
\r
");
foreach (BlogInfo info3 in XmlDb.Blogs)
{
__w.Write("\r
\t<a href=\"");
__w.Write(info3.Href);
__w.Write("\" target=\"_blank\">");
__w.Write(info3.Title);
__w.Write("</a><br />\r
");
}
__w.Write("\r
<hr />\r
\r
");
foreach (BlogInfo info4 in XmlDb.Blogs)
{
__w.Write("\r
\t<a href=\"");
__w.Write(info4.Href);
__w.Write("\" target=\"_blank\">");
__w.Write(info4.Title);
__w.Write("</a><br />\r
");
}
__w.Write("\r
<hr />\r
\r
");
foreach (BlogInfo info5 in XmlDb.Blogs)
{
__w.Write("\r
\t<a href=\"");
__w.Write(info5.Href);
__w.Write("\" target=\"_blank\">");
__w.Write(info5.Title);
__w.Write("</a><br />\r
");
}
__w.Write("\r
<hr />\r
\r
</body>\r
</html>\r
");
}
[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 와 testpagewebfrompage_aspx 의 컴 파일 결 과 는 완전히 다르다.가장 큰 차 이 는 testpageinlinepage_aspx 방법 이 있 습 니 다:Render__control 1 이 방법 에서 페이지 의 내용 은 HtmlTextWriter 대상 에 직접 기 록 됩 니 다.한 가지 더 알려 드 리 고 싶 은 것 이 있 습 니 다.모든 Control 의 출력 은 마지막 으로 자신의 디 스 플레이 코드 를 HtmlTextWriter 대상 에 기록 해 야 합 니 다.그래서 여기 서 testpage 를 뚜렷하게 볼 수 있 습 니 다.inlinepage_서버 컨트롤 이 없 기 때문에 aspx 의 실행 속도 가 매우 빨 라 야 합 니 다.2.모든 컨트롤 을 재 귀적 으로 순환 할 필요 가 없고 모든 컨트롤 의 생명주기 호출 비용 도 절약 된다.3.서버 컨트롤 대상 을 만 들 지 않 아 도 GC 의 압력 이 많이 줄어든다.4.수출 방식 이 더욱 효율 적 이다.앞의 분석 을 통 해 두 페이지 의 실행 속도 가 왜 6 배 차이 가 나 는 지 이 유 를 알 게 되 었 습 니 다.아직 설명 이 없 는 것 같 습 니 다.Render__control 1 은 어떻게 호출 됩 니까?ASPX 페이지 를 비롯 한 WebForm 프로 그래 밍 모델 은 실행 할 때 모든 컨트롤 을 재 귀적 으로 순환 하 는 특징 이 있다 는 것 을 잘 알 고 있 습 니 다.페이지 는 Render 단계 에서 출력 되 고 페이지 의 HTML 코드 도 그 단계 에서 HtmlTextWriter 대상 에 출력 됩 니 다.하지만,testpageinlinepage_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__control 1 방법.코드 를 통 해 알 수 있 듯 이 if 구문 블록 에 들 어 갔다 면 모든 컨트롤 을 재 귀적 으로 순환 하고 컨트롤 을 호출 하 는 Render 방법 을 사용 하지 않 아 도 됩 니 다.그렇다면 어떻게 if 구문 블록 에 들 어 갈 수 있 습 니까?정 답 은 control.SetRender MethodDelegate 방법 을 호출 하 는 것 이다.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.912738 이 또 조금 빨 라 졌 다.설명:이번 성능 최 적 화 를 위해 MyMVC 프레임 워 크 도 약간의 조정 을 했다.이전에 이 프레임 워 크 를 다운로드 한 적 이 있다 면 다시 다운로드 하 십시오.상단 분석 최적화 결과 2.앞의 분석 을 통 해 우 리 는 서버 컨트롤 대상 을 만 들 지 않 고 그들의 생명 주 기 를 호출 하지 않 으 면 페이지 의 실행 속도 가 매우 빠르다 는 것 을 알 고 있다.다시 한 번 상상 해 보 세 요:페이지 에 도 생명 주기 가 있 습 니 다.그리고 생명 주기의 절차 가 더 길 고 생략 하 는 것 이 더 빠 르 지 않 습 니까?그러나 Render 방법 은 Public 방법 이 아 닙 니 다.우 리 는 아직 직접 호출 할 수 없 지만 Render Control 방법 으로 이 과정 을 실현 할 수 있 습 니 다.페이지 의 수명 주 기 를 뛰 어 넘 기 때문에 모판 페이지 를 포함 한 모든 서버 컨트롤 을 사용 할 수 없습니다.그래서 저 는 앞에서 테스트 할 때 사용 하 는 코드 를 사용자 컨트롤 로 옮 긴 다음 에 사용자 컨트롤 을 Page 에 불 러 와 서 테스트 하 겠 습 니 다.테스트 용례 3 은 테스트 용례 2 에 비해 테스트 과정 에서 페이지 의 생명 주 기 를 뛰 어 넘 었 기 때문에 속도 도 빠르다.응,기본적으로 이 간단 한 이유 지.이 방법 은 아무런 컨트롤 수명 주기 가 없 기 때문에 속도 가 가장 빠르다.이 일련의 최 적 화 를 통 해 페이지 의 집행 시간 은 최종 적 으로 00:00:07.5607229 에서 00:00:00.9132738예제 코드 를 다운로드 하려 면 여 기 를 누 르 십시오.로 감소 했다.

좋은 웹페이지 즐겨찾기