#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:
-
Открепление / повторная привязка не являются потокобезопасными (AFAIK нигде не указан в xmldoc). Симптом: периодически вы можете потерять некоторые привязки из-за дублирования ключа во внутреннем словаре Kenrel.
-
Ссылка на пользовательский объект области из целевого объекта привязки может вызвать утечку памяти (это на самом деле разумно, но 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.Веб-хостинг)