Проблема и производительность

#c# #performance #ninject

#c# #Производительность #ninject

Вопрос:

Я провожу проверку кода на веб-сайте, на котором одновременно будет много пользователей, около 100 000 прошедших проверку подлинности пользователей.

Я нашел следующий код типа:

     [Inject]
    public BusinessLayer.ILoginManager LoginManager { get; set; }
  

И в global.asax.cs:

    protected Ninject.IKernel CreateKernel()
    {
        return new StandardKernel(new ServiceModule());
    }


    internal class ServiceModule : NinjectModule
    {

        public override void Load()
        {
             Kernel.Bind<IReportProxy>().To<ReportProxy>().InRequestScope();
        }
    }
  

Вопрос в том, повлияет ли использование Ninject на производительность? Существуют ли ситуации, в которых вам не следует использовать Ninject из-за производительности?

Ответ №1:

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

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

Комментарии:

1. Верно, но у всех разные API и наборы функций. Рассмотрите возможность принятия решения на основе ряда факторов, таких как API, поддержка целевых сроков службы (например, для веб-запросов в веб-приложениях достаточно), производительность для целевого использования, лицензирование и т.д…

Ответ №2:

Ninject причинил нам много проблем, связанных с производительностью проекта. Это один из самых медленных DI, и я бы настоятельно рекомендовал рассмотреть другой движок DI (напримерhttps://github.com/ninject/ninject/issues/84)

Пара других моментов, которые следует отметить о Ninject:

  1. Открепление / повторная привязка не являются потокобезопасными (AFAIK нигде не указан в xmldoc). Симптом: периодически вы можете потерять некоторые привязки из-за дублирования ключа во внутреннем словаре Kenrel.

  2. Ссылка на пользовательский объект области из целевого объекта привязки может вызвать утечку памяти (это на самом деле разумно, но Ninject никоим образом не помогает в поиске проблемы). Например. Привязать объект, который имеет постоянную ссылку на HttpContext в области HttpContext.Current

Также стоит иметь в виду, что переключение на другой DI может оказаться невозможным в зависимости от набора функций, который вы в конечном итоге будете использовать (например, местоположение службы, условные привязки, пользовательские области, динамические привязки и т.д.). Даже если другая платформа DI имеет аналогичный набор функций (например, LightInject), синтаксис может слишком отличаться.

Комментарии:

1. Я могу настоятельно рекомендовать просмотреть ссылку на ошибку, предоставленную @bushed. Это приводит к отличному критерию производительности IoC для многих фреймворков.

Ответ №3:

Я наткнулся на этот вопрос, когда заметил, что внедрение свойства (через [Inject] и kernel.Inject(instance) внутри контроллера) заняло около 3 секунд, что сильно задержало обработку запросов для конкретного контроллера. Большинство других контроллеров пострадали в меньшей степени.

Краткий ответ

Да, Ninject явно влечет за собой накладные расходы, но я обнаружил, что это зависит от трех факторов: версии библиотеки, размера дерева зависимостей и того, как решается проблема зависимости.

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

Длинный ответ

1. Шаблон внедрения — я столкнулся с проблемами производительности при использовании внедрения свойств. Быстрая победа заключалась в его замене prop => kernel.Get<IFoo>() , но этот шаблон не рекомендуется (3.3.4 помечает прямое использование ядра как устаревшее). Однако это сократило время, необходимое для решения ссылки, без выполнения серьезного рефакторинга.

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

3. Версия библиотеки — Я обновил библиотеку с 3.2.0 до 3.3.4 и заметил значительное улучшение производительности. Однако я заплатил цену за многочисленные изменения внутри приложения (переход с NinjectWebCommon на MvcApplication и обновление различных библиотек, таких как Castle.Ядро, Ninject.MockingKernel, Ninject.Ядро-макет.NSubstitute, Ninject.Web.Common.Веб-хостинг)