ASP.NET MVC URL生成性能

15

一个使用ASP.NET MVC进行的小型基准测试。Viewpage代码:

    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")) ) %>

在典型的Core2笔记本电脑上以ASP.NET MVC Beta默认新项目模板运行此代码,结果如下:

38毫秒,每个链接0.038毫秒

120毫秒,每个链接0.12毫秒

54毫秒,每个链接0.054毫秒

在一个包含大约10个控制器、总共约100个方法和30个路由表条目的生产项目上运行相同的基准测试时,基于表达式的方法性能显著降低:

31毫秒,每个链接0.031毫秒

112毫秒,每个链接0.112毫秒

450毫秒,每个链接0.45毫秒

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

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

据说Stack Overflow也是由同一框架驱动的,你们是如何解决这个扩展问题的?大量缓存前端页面(有很多链接)和预渲染控件吗?

还有其他在ASP.NET MVC中存在性能问题或有些好技巧的生产网站吗?


这是一个你可能会觉得有用的链接:http://blog.whiletrue.com/2009/04/aspnet-mvc-performance/ - Nik
@Nik:实际上,那个演示文稿的作者就是我,所以嗯...是的。 :) - rudib
有人知道ASP.NET MVC2是否仍存在此问题吗? - Pure.Krome
4个回答

4

我在微软论坛上提出了这个问题,得到了一个来自MS MVC开发人员的答案。

该帖子

答案

从MVC Preview 2到昨天发布的MVC Beta,Routing发生了很多变化。其中一些变化包括性能提升。以下是使应用程序中的URL生成更具性能的一些技巧: 1. 使用命名路由。命名路由是路由的可选功能。名称仅适用于URL生成 - 它们永远不会用于匹配传入的URL。当您在生成URL时指定名称,我们将仅尝试匹配该路由。这意味着即使您指定的命名路由是路由表中的第100个路由,我们也会直接跳转到它并尝试匹配。 2. 将最常见的路由放在路由表的开头。这将改善URL生成和处理传入URL的性能。路由基于规则:第一个匹配获胜。如果第一个匹配是路由表中的第100个路由,那么这意味着它必须尝试99个其他路由,并且没有一个匹配。 3. 不要使用URL生成。有些人喜欢它,有些人不喜欢。它有点棘手。如果您的URL非常动态,则使用它很好,但是当您开始的URL非常少且可能不关心它们的确切外观时,它可能会有点麻烦。 我的最爱是#1,因为它非常容易使用,而且还可以从应用程序开发人员的角度(也就是您!)使URL生成更具确定性。

1
问题:使用命名路由 <-- 什么是命名路由?如何使用重载?谢谢 :) - Pure.Krome
如果你还在关心的话:在你的 global.asax 文件中,你使用 routes.MapRoute("routeName", yadiyadiya) 来定义路由。然后在你的 action 中,你可以使用 RedirectToRoute("routeName", viewData) 进行重定向。可能还有更多相关内容。 - Boris Callens

1

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

除非您开始以可配置的形式定义路由(例如 web.config 或数据库),否则您需要稍微缩小一点规模。

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

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


1

好的,在空白模板项目上增加两个指标:

<%= 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毫秒,每个链接0.071毫秒

35毫秒,每个链接0.035毫秒

虽然代码更糟糕了,但性能大大提高。可惜啊。


0
缓存链接可能是团队的一个好建议,因为它们在进程的生命周期内不会改变(对于大多数应用程序而言)。但是,据我所知,你无法缓存链接,因为你需要缓存执行的方法,这发生在路由解析之后,这是较慢的部分。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接