技术开发 频道

ASP.NET页面性能提升8倍的优化方法


  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的回收以及内存占用的影响也是不可忽视的。
 

0
相关文章