Производительность генерации URL ASP.NET MVC

Небольшой бенчмарк с 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")) ) %>

Выполнение этого на типичном блокноте Core2 в шаблоне нового проекта по умолчанию с бета-версией ASP.NET MVC дает следующие результаты:

38 мс, 0,038 мс на канал

120 мс, 0,12 мс на канал

54 мс, 0,054 мс на ссылку

Запустив тот же тест в производственном проекте с примерно 10 контроллерами, которые имеют всего около 100 методов и 30 записей в таблице маршрутизации, производительность метода на основе выражений значительно снижается:

31 мс, 0,031 мс на канал

112 мс, 0,112 мс на канал

450 мс, 0,45 мс на канал

Мы довольно часто используем этот метод (ремонтопригодность) и проводим некоторые тесты производительности, это сильно снижает производительность сайта - страницы быстро содержат около 30 или более таких ссылок, что означает 10 мс дополнительных накладных расходов на одну страницу. Даже 0,112 мс на URL — это около 4 мс чистой нагрузки ЦП.

Следует отметить, что производительность всех трех вызовов генерации URL между MVC Preview 3 и Beta (выпущенной вчера) улучшилась в 5 раз.

Предполагается, что Stack Overflow работает на той же платформе, как вы, ребята, решили эту проблему масштабирования? Либеральное кеширование главной страницы (много ссылок) и предварительно обработанные элементы управления?

Любые другие производственные веб-сайты в ASP.NET MVC с проблемами производительности или какие-либо полезные советы?


person rudib    schedule 17.10.2008    source источник
comment
Вот ссылка, которая может оказаться полезной: blog.whiletrue.com/2009/ 04/aspnet-mvc-производительность   -  person Nik    schedule 16.05.2009
comment
@Nik: На самом деле, я автор этой презентации, так что... Да. :)   -  person rudib    schedule 18.05.2009
comment
Кто-нибудь знает, по-прежнему ли это проблема с ASP.NET MVC2?   -  person Pure.Krome    schedule 04.10.2010


Ответы (4)


Я задал этот вопрос на форумах MS, и получил ответ от разработчика MS MVC.

Сообщение

Ответ

От MVC Preview 2 до недавно выпущенной бета-версии MVC со вчерашнего дня в маршрутизации было много изменений. Некоторые из этих изменений включают улучшения производительности. Вот несколько приемов, позволяющих повысить производительность генерации URL в вашем приложении:

  1. Используйте именованные маршруты. Именованные маршруты являются дополнительной функцией маршрутизации. Имена применяются только для генерации URL-адресов — они никогда не используются для сопоставления входящих URL-адресов. Когда вы указываете имя при создании URL-адреса, мы пытаемся сопоставить только этот единственный маршрут. Это означает, что даже если указанный вами именованный маршрут является сотым маршрутом в таблице маршрутов, мы перейдем прямо к нему и попытаемся сопоставить.

  2. Поместите наиболее распространенные маршруты в начало таблицы маршрутов. Это повысит производительность как генерации URL-адресов, так и обработки входящих URL-адресов. Маршрутизация работает по правилу, согласно которому выигрывает первое совпадение. Если первое совпадение — это 100-й маршрут в вашей таблице маршрутов, это означает, что ему пришлось перепробовать 99 других маршрутов, и ни один из них не совпал.

  3. Не используйте генерацию URL. Кому-то это нравится, кому-то нет. Это немного сложно освоить. Это приятно использовать, если ваши URL-адреса очень динамичны, но это может быть немного хлопотно, когда у вас очень мало URL-адресов для начала, и, возможно, вас не волнует, как именно они выглядят.

Мой любимый вариант — № 1, так как он очень прост в использовании, а также делает генерацию URL более детерминированной с точки зрения разработчика приложения (это вы!).

person CVertex    schedule 19.10.2008
comment
Вопрос: Используйте именованные маршруты ‹ -- что такое именованный маршрут? какую перегрузку использовать? ваше здоровье :) - person Pure.Krome; 28.11.2008
comment
Если вам все еще не все равно: в вашем файле global.asax вы используете маршруты.MapRoute(routeName, yadiyadiya); Затем в своих действиях вы можете выполнить RedirectToRoute(routeName, viewData); Где-то есть еще, наверное - person Boris Callens; 17.12.2008

Кэширование ссылок, вероятно, было бы хорошим предложением для команды, поскольку они не изменятся в течение всего процесса (во всяком случае, для большинства приложений).

Пока вы не начнете определять свои маршруты в настраиваемой форме (такой как web.config или в базе данных), вам придется немного уменьшить масштаб.

Я подозреваю, что большая часть задержки в среднем примере связана с анонимным типом, который автоматически преобразуется в словарь. Кэширование URL-адреса здесь не поможет, потому что вам все равно нужно отразить этот тип.

Тем временем вы можете создать свои собственные вспомогательные методы для некоторых из этих ссылок на основе словаря, которые принимают именно те входные данные, которые вам нужны. Тогда вы можете справиться с кэшированием самостоятельно.

person Ben Scheirman    schedule 17.10.2008

Хорошо, две дополнительные метрики в проекте с пустым шаблоном:

<%= 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 мс на канал

Гораздо лучшая производительность с более неприятным кодом. Очень жаль.

person rudib    schedule 17.10.2008

Кэширование ссылок, вероятно, было бы хорошим предложением для команды, поскольку они не изменятся в течение всего процесса (во всяком случае, для большинства приложений).

Как вы можете кэшировать ссылки, вы не можете этого сделать, насколько я знаю, потому что вам нужно кэшировать метод, который выполняется, что происходит после разрешения маршрута, что является медленной частью.

person bashmohandes    schedule 17.10.2008