Razor视图的性能分析

时间:2018-08-11 12:42:16

标签: c# performance razor asp.net-core .net-core

我正在研究一个项目,在该项目中我们呈现一种文章列表,其中包含许多可选的图像和文本属性,并且全部采用“花哨的”非表格格式,以适应现有/缺少的属性并增加了一些随机性。客户想要随意的外观,最后我们得到了一棵大树,每层深度分别为4和3-10。每个模板都非常简单,并且没有“魔术”。

在负载测试期间,我们发现对于大型文章列表,我们在视图渲染中存在性能问题。渲染5篇文章需要20毫秒,而渲染60篇文章则需要1秒。

是否有一种聪明的方法来衡量每个模板的渲染时间?我想避免在所有地方手动添加秒表。有没有框架的方法?在一般情况下,如何调试此类问题是否有建议?我什么都找不到。

1 个答案:

答案 0 :(得分:0)

我自己找到了一个好的解决方案:

public class RazorPerformanceDiagnosticListener
{
    private readonly IDictionary<string, TemplatePerformanceHolder> _timers = new ConcurrentDictionary<string, TemplatePerformanceHolder>();

    [DiagnosticName("Microsoft.AspNetCore.Mvc.Razor.BeginInstrumentationContext")]
    public virtual void OnBeginInstrumentationContext(HttpContext httpContext, string path, int position, int length, bool isLiteral)
    {
        if (_timers.ContainsKey(path))
        {
            _timers[path].ContextDepth++;
        }
        else
        {
            _timers[path] = new TemplatePerformanceHolder(){ContextDepth = 1, Stopwatch = Stopwatch.StartNew() };
        }
    }

    [DiagnosticName("Microsoft.AspNetCore.Mvc.Razor.EndInstrumentationContext")]
    public virtual void OnEndInstrumentationContext(HttpContext httpContext, string path)
    {
        _timers[path].ContextDepth--;

        if (_timers[path].ContextDepth == 0)
        {
            _timers[path].Stopwatch.Stop();
            //log _timers[path].Stopwatch.Elapsed
            _timers.Remove(path);
        }
    }
}

public class TemplatePerformanceHolder
{
    public Stopwatch Stopwatch;
    public int ContextDepth;
}

和Startup.cs

using System.Diagnostics;

public void Configure(DiagnosticListener diagnosticListener)
{
    diagnosticListener.SubscribeWithAdapter(new RazorPerformanceDiagnosticListener());
}

如果您想知道为什么需要保持上下文深度:这些BeginInstrumentationContext事件在一个剃刀模板(EndInstrumentationContext也是如此)中被多次触发,因此每个模板都有一个堆栈。

还请记住,此代码将在并发请求(或并行化模板渲染)中遇到问题。要解决此问题,您需要使HttpContext以及线程id可能成为Dictionary键的一部分。但是我不需要“生产就绪”代码,所以要小心。

基于this