ASP.NET MVC URL生成性能

时间:2022-05-02 05:52:27

A little benchmark with ASP.NET MVC. Viewpage code:

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/>";
    }

View code:

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

Running this on a typical Core2 notebook on the default new project template with ASP.NET MVC Beta yields these results:

使用ASP.NET MVC Beta在默认的新项目模板上的典型Core2笔记本上运行此命令会产生以下结果:

38 ms, 0,038 ms per link

38 ms,每个链接0,038 ms

120 ms, 0,12 ms per link

120 ms,每个链接0,12 ms

54 ms, 0,054 ms per link

54 ms,每个链接0,054 ms

Running the same benchmark on a production project with about 10 controllers that have all in all around 100 methods and 30 routing table entries, the performance degrades greatly for the expression-based method:

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

31 ms, 0,031 ms per link

31 ms,每个链接0,031 ms

112 ms, 0,112 ms per link

每个链路112毫秒,0,112毫秒

450 ms, 0,45 ms per link

每个链路450毫秒,0.45毫秒

We use this method quite a lot (maintainability) and doing some performance benchmarking, this degrades the performance of the site greatly - pages quickly contain around 30 or more of such links, that means 10ms of additional overhead on a single page. Even 0.112ms per an URL is around 4ms of pure CPU overhead.

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

It should be noted that performance of all the three URL generation calls between MVC Preview 3 and Beta (released yesterday) got improved by a factor of 5.

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

Stack Overflow is supposedly powered by the same framework, how have you guys tackled this scaling problem? Liberal caching of the front page (lots of links) and pre-rendered controls?

Stack Overflow应该由同一个框架提供支持,你们如何解决这个扩展问题呢?*缓存首页(许多链接)和预渲染控件?

Any other production websites in ASP.NET MVC with performance issues or some good tips?

ASP.NET MVC中的任何其他生产网站都存在性能问题或一些好的提示?

4 个解决方案

#1


4  

I asked this question on the MS forums, which got an answer from an MS MVC developer.

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

The post

The answer

From MVC Preview 2 to the recently released MVC Beta from yesterday there have been a lot of changes to Routing. Some of those changes include performance improvements. Here are some tricks to make URL generation more performant in your application:

从MVC Preview 2到最近发布的MVC Beta,从昨天开始,路由已经发生了很多变化。其中一些变化包括性能改进。以下是一些技巧,可以使您的应用程序中的URL生成更加高效:

  1. Use named routes. Named routes are an optional feature of routing. The names only apply to URL generation - they are never used for matching incoming URLs. When you specify a name when generating a URL we will only try to match that one route. This means that even if the named route you specified is the 100th route in the route table we'll jump straight to it and try to match.

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

  2. Put your most common routes at the beginning of the route table. This will improve performance of both URL generation as well as processing incoming URLs. Routing works based on the rule that the first match wins. If the first match is the 100th route in your route table, then that means it had to try 99 other routes and none of them matched.

    将最常见的路由放在路由表的开头。这将提高URL生成的性能以及处理传入的URL。路由基于第一个匹配获胜的规则工作。如果第一个匹配是路由表中的第100个路由,那么这意味着它必须尝试99个其他路由并且它们都不匹配。

  3. Don't use URL generation. Some people like it, some people don't. It's a bit tricky to master. It's nice to use if your URLs are very dynamic but it can be a bit of a hassle when you have very few URLs to begin with and perhaps you don't care about exactly what they look like.

    不要使用URL生成。有些人喜欢它,有些人喜欢。掌握它有点棘手。如果您的网址非常动态,那么使用它会很好,但是当您开始使用的网址很少时可能会有点麻烦,也许您根本不关心它们的外观。

My favorite option is #1 since it's super easy to use and it also makes URL generation more deterministic from the app developer's perspective (that's you!).

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

#2


1  

Caching links would probably be a good suggestion for the team, as they won't change for the life of the process (for most apps anyway).

缓存链接可能对团队来说是一个很好的建议,因为它们不会在流程的整个过程中发生变化(对于大多数应用程序而言)。

Until you start defining your routes in a configurable form (such as web.config or in a database) then you'd have to scale back a bit.

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

I suspect that a big portion of the delay on the middle example is the anonymous type that gets automatically converted to a dictionary. Caching the URL wouldn't help here b/c you'd still need to reflect that type.

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

In the meantime, you can create your own helper methods for some of those dictionary-based links that take the exact input you require. Then you can handle the caching yourself.

与此同时,您可以为某些基于字典的链接创建自己的帮助器方法,这些链接可以获取您需要的确切输入。然后你可以自己处理缓存。

#3


1  

Ok, two additional metrics on the blank template project:

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

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

Results:

71 ms, 0,071 ms per link

每个链路71毫秒,0,071毫秒

35 ms, 0,035 ms per link

35 ms,每个链接0,035 ms

Much better performance with way nastier code. Too bad.

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

#4


0  

Caching links would probably be a good suggestion for the team, as they won't change for the life of the process (for most apps anyway).

缓存链接可能对团队来说是一个很好的建议,因为它们不会在流程的整个过程中发生变化(对于大多数应用程序而言)。

How can you cache links, you can't do that as far as I know, because you need to cache the method that gets executed, which happens after the route gets resolved, which is the slow part.

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

#1


4  

I asked this question on the MS forums, which got an answer from an MS MVC developer.

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

The post

The answer

From MVC Preview 2 to the recently released MVC Beta from yesterday there have been a lot of changes to Routing. Some of those changes include performance improvements. Here are some tricks to make URL generation more performant in your application:

从MVC Preview 2到最近发布的MVC Beta,从昨天开始,路由已经发生了很多变化。其中一些变化包括性能改进。以下是一些技巧,可以使您的应用程序中的URL生成更加高效:

  1. Use named routes. Named routes are an optional feature of routing. The names only apply to URL generation - they are never used for matching incoming URLs. When you specify a name when generating a URL we will only try to match that one route. This means that even if the named route you specified is the 100th route in the route table we'll jump straight to it and try to match.

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

  2. Put your most common routes at the beginning of the route table. This will improve performance of both URL generation as well as processing incoming URLs. Routing works based on the rule that the first match wins. If the first match is the 100th route in your route table, then that means it had to try 99 other routes and none of them matched.

    将最常见的路由放在路由表的开头。这将提高URL生成的性能以及处理传入的URL。路由基于第一个匹配获胜的规则工作。如果第一个匹配是路由表中的第100个路由,那么这意味着它必须尝试99个其他路由并且它们都不匹配。

  3. Don't use URL generation. Some people like it, some people don't. It's a bit tricky to master. It's nice to use if your URLs are very dynamic but it can be a bit of a hassle when you have very few URLs to begin with and perhaps you don't care about exactly what they look like.

    不要使用URL生成。有些人喜欢它,有些人喜欢。掌握它有点棘手。如果您的网址非常动态,那么使用它会很好,但是当您开始使用的网址很少时可能会有点麻烦,也许您根本不关心它们的外观。

My favorite option is #1 since it's super easy to use and it also makes URL generation more deterministic from the app developer's perspective (that's you!).

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

#2


1  

Caching links would probably be a good suggestion for the team, as they won't change for the life of the process (for most apps anyway).

缓存链接可能对团队来说是一个很好的建议,因为它们不会在流程的整个过程中发生变化(对于大多数应用程序而言)。

Until you start defining your routes in a configurable form (such as web.config or in a database) then you'd have to scale back a bit.

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

I suspect that a big portion of the delay on the middle example is the anonymous type that gets automatically converted to a dictionary. Caching the URL wouldn't help here b/c you'd still need to reflect that type.

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

In the meantime, you can create your own helper methods for some of those dictionary-based links that take the exact input you require. Then you can handle the caching yourself.

与此同时,您可以为某些基于字典的链接创建自己的帮助器方法,这些链接可以获取您需要的确切输入。然后你可以自己处理缓存。

#3


1  

Ok, two additional metrics on the blank template project:

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

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

Results:

71 ms, 0,071 ms per link

每个链路71毫秒,0,071毫秒

35 ms, 0,035 ms per link

35 ms,每个链接0,035 ms

Much better performance with way nastier code. Too bad.

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

#4


0  

Caching links would probably be a good suggestion for the team, as they won't change for the life of the process (for most apps anyway).

缓存链接可能对团队来说是一个很好的建议,因为它们不会在流程的整个过程中发生变化(对于大多数应用程序而言)。

How can you cache links, you can't do that as far as I know, because you need to cache the method that gets executed, which happens after the route gets resolved, which is the slow part.

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