ASP.NET MVC URL生成性能

本文关键字:性能 URL NET MVC ASP | 更新日期: 2023-09-27 17:47:48

ASP的一个小基准测试。NET MVC。查看页面代码:

    public string Bechmark(Func<string> url)
    {
        var s = new Stopwatch();
        var n = 1000;
        s.Reset();
        s.Start();
        for (int i = 0; i < n; i++)
        {
            var u = url();
        }
        s.Stop();
        return s.ElapsedMilliseconds + " ms, " + ((s.ElapsedMilliseconds) / (float)n) + " ms per link<br/>";
    }

查看代码:

<%= Bechmark(() => Url.Action("Login", "Account")) %>
<%= Bechmark(() => Url.Action("Login", "Account", new {username="bla", password="bla2", returnurl="blabla32", rememberme=false} )) %>
<%= Bechmark(() => Html.BuildUrlFromExpression<AccountController>(a=>a.ChangePassword("bla", "bla", "ya")) ) %>

在带有ASP的默认新项目模板上的典型Core2笔记本上运行此程序。NET MVC Beta产生以下结果:

38毫秒,0038毫秒/链路

120毫秒,每条链路0,12毫秒

54毫秒,每个链路0054毫秒

在一个生产项目上运行相同的基准测试,该项目有大约10个控制器,这些控制器总共有大约100个方法和30个路由表条目,基于表达式的方法的性能会大大降低:

每个链路 31毫秒,0031毫秒

112毫秒,每条链路0112毫秒

450毫秒,每条链路0,45毫秒

我们经常使用这种方法(可维护性),并进行一些性能基准测试,这会大大降低网站的性能——页面很快包含大约30个或更多这样的链接,这意味着单个页面上会有10ms的额外开销。即使每个URL的0.112ms也相当于4ms的纯CPU开销。

需要注意的是,MVC Preview 3和Beta(昨天发布)之间的所有三个URL生成调用的性能都提高了5倍。

Stack Overflow据说是由同一个框架提供的,你们是如何解决这个伸缩问题的?自由缓存首页(大量链接)和预渲染控件?

ASP中的任何其他制作网站。NET MVC的性能问题还是一些好的提示?

ASP.NET MVC URL生成性能

我在MS论坛上问了这个问题,得到了一位MS MVC开发人员的回答。

答案

从MVC预览版2到昨天发布的MVC Beta版,路由有很多变化。其中一些变化包括性能改进。以下是一些使URL生成在应用程序中更具性能的技巧:

  1. 使用命名管线。命名路由是路由的可选功能。这些名称仅适用于URL生成-它们从不用于匹配传入的URL。当您在生成URL时指定名称时,我们将只尝试匹配这一条路由。这意味着,即使您指定的命名路由是路由表中的第100条路由,我们也会直接跳到它并尝试匹配。

  2. 将最常用的路线放在路线表的开头。这将提高URL生成和处理传入URL的性能。路由是根据第一场比赛获胜的规则进行的。如果第一条匹配是路由表中的第100条路由,那么这意味着它必须尝试99条其他路由,但没有一条匹配。

  3. 不要使用URL生成。有些人喜欢,有些人不喜欢。掌握起来有点难。如果你的URL非常动态,那么使用它是很好的,但当你一开始只有很少的URL,而且你可能不在乎它们到底是什么样子时,这可能会有点麻烦。

我最喜欢的选项是#1,因为它非常容易使用,而且从应用程序开发人员的角度来看,它还使URL生成更具确定性(就是你!)。

缓存链接可能是团队的一个好建议,因为它们在流程的生命周期内不会改变(无论如何,对于大多数应用程序来说)。

在您开始以可配置的形式(如web.config或数据库)定义路由之前,您必须稍微缩减规模。

我怀疑中间示例的延迟很大一部分是自动转换为字典的匿名类型。缓存URL在这里没有帮助b/c您仍然需要反映该类型。

同时,您可以为一些基于字典的链接创建自己的辅助方法,这些链接可以获得所需的确切输入。然后您可以自己处理缓存。

好的,空白模板项目上的两个额外指标:

<%= Bechmark(() => Url.Action("Login", "Account", new Dictionary<string, object> {{"username", "bla"}, {"password", "bla2"}, {"returnurl", "blabla32"}, {"rememberme", "false"}})) %>
<%= Bechmark(() => Url.Action("Login", "Account", new RouteValueDictionary(new Dictionary<string, object> {{"username", "bla"}, {"password", "bla2"}, {"returnurl", "blabla32"}, {"rememberme", "false"}}))) %>

结果:

每个链路 71毫秒,0071毫秒

35毫秒,每个链路0035毫秒

使用更糟糕的代码可以获得更好的性能。太糟糕了。

缓存链接可能是个不错的选择给团队的建议,因为他们不会改变生命的过程(对于大多数应用程序)。

你如何缓存链接,据我所知,你不能这样做,因为你需要缓存被执行的方法,这发生在路由被解析之后,这是缓慢的部分。