Производительность и использование Resolve в Unity - PullRequest
2 голосов
/ 10 февраля 2012

Мы используем Unity в качестве нашего контейнера МОК.

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

Это, однако, приводит к разрешению интерфейса внутри цикла. Это может привести к разрешению интерфейса 100 000 раз за один запуск.

Вопрос в том, будет ли перемещение разрешения вне цикла иметь существенную разницу или это просто микрооптимизация?

Наша программа работает более суток. Таким образом, для тех, кто ответит «проверь это сам», на самом деле быстрее задать вопрос здесь:)

Ответы [ 5 ]

4 голосов
/ 10 февраля 2012

Я бы сказал, это зависит от того, как вы зарегистрировали интерфейс. С каким LifetimeManager вы его зарегистрировали?
Ваша программа всегда нуждается в новом экземпляре? Или это может быть один и тот же экземпляр снова и снова?

Если вам нужен тот же экземпляр (Singleton), используйте ContainerControlledLifetimeManager:

Container.RegisterType<Interface, Implementation>(new ContainerControlledLifetimeManager());

Если вам не важно, какой экземпляр вы получите (новый или старый, поддерживаемый GC), вы можете использовать ExternallyControlledLifeTimeManager:

Container.RegisterType<Interface, Implementation>(new ExternallyControlledLifeTimeManager());

Вы также можете создать собственную реализацию LifetimeManager, чтобы лучше соответствовать вашим потребностям.

Взгляните на эту статью о LifetimeManagers

1 голос
/ 10 февраля 2012

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

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

Опять же, никто, кроме вас, не может сказать, если ваши проблемы со скоростьювызвано контейнером.Мы не знаем, что вы делаете в этом цикле из 100 000 итераций, и вполне возможно, что это накладные расходы на разрешение интерфейсов, если <1% времени вы тратите внутри самого цикла.Не ждите дня, запустите его всего за 1000 итераций, и вы увидите ... </p>

Также вам не нужно запускать бизнес-логику, просто реализуйте подобный цикл и разрешайте только свои интерфейсы тамТаким образом, вы можете увидеть, как Unity влияет на ваше приложение.

Но в любом случае, 100 000 разрешений за более чем 1 день означает ~ 2 секунды ... Это дало бы эффект, но не ЭТО драматично ... Я бы лучше посмотрел, что вы можете оптимизировать в своей бизнес-логике,или паралеллизуйте ваш цикл.

Также Unity не имеет репутации самого быстрого контейнера за всю историю (на самом деле это совсем наоборот);) Вы можете попробовать Autofac, который значительно быстрее ...

Вот некоторые тесты производительности для контейнеров IoC .

1 голос
/ 10 февраля 2012

Это, конечно, повлияет на производительность.Сколько зависит от сложности графа зависимостей, который имеет построенный объект, и от того, созданы ли какие-либо ресурсы (например, соединения db и т. Д.).

Как говорит Unity, это не самый быстрый и не самый медленный контейнер.Примерно в среднем.

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

1 голос
/ 10 февраля 2012

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

Я собрал очень наивный тест, в котором результаты разрешения на порядок медленнее, но не медленнее. Конечно, это не учитывает то, что еще может быть зарегистрировано в контейнере, или количество управляемых экземпляров, или то, что создается, или любое количество других факторов, которые я пропустил. ИМХО, единственный способ действительно ответить на ваш вопрос - протестировать приложение, извините: (

RESULTS:
00:00:00.2462702 : Resolve ContainerControlledLifetimeManager
00:00:00.0014184 : Plain assignment
00:00:00.3514334 : Resolve PerResolveLifetimeManager 
00:00:00.0019258 : Direct instantiation


class Program
{
    static readonly IUnityContainer _container = new UnityContainer();

    static void Main(string[] args)
    {
        _container.RegisterType(typeof(IInterfaceOne), typeof (ClassOne), new ContainerControlledLifetimeManager());
        _container.RegisterType(typeof(IInterfaceTwo), typeof(ClassTwo), new PerResolveLifetimeManager());

        var classOne = new ClassOne();

        DoLots("Resolve ContainerControlledLifetimeManager", ()=>_container.Resolve<IInterfaceOne>());
        DoLots("Plain assignment", () =>classOne);

        DoLots("Resolve PerResolveLifetimeManager ", () => _container.Resolve<IInterfaceTwo>());
        DoLots("Direct instantiation", () => new ClassTwo());

        Console.ReadLine();
    }

    static void DoLots(string msg, Func<object> resolveFunc)
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        for (int i = 0; i < 100000; i++)
        {
            var instance = resolveFunc();
        }
        stopwatch.Stop();

        Console.WriteLine(string.Format("{0} : {1}",stopwatch.Elapsed , msg ));
    }
}

public interface IInterfaceOne{}
public interface IInterfaceTwo{}

public class ClassOne : IInterfaceOne{}
public class ClassTwo : IInterfaceTwo{}
0 голосов
/ 15 июня 2015

Этот вопрос немного устарел, но я нашел, что при использовании Unity для повышения производительности я принудительно установил singleton, ContainerControlledLifetimeManager, экземпляры (упомянутые в ответе Роэлса выше) любых объектов, кроме контроллеров.Контроллеры должны быть новыми экземплярами каждый раз, когда их вызывают.Я использовал следующий код в методе Bootstrap.cs / RegisterTypes, который вызывается в файле global.asax.

var controllerClasses = AllClasses.FromLoadedAssemblies()
    .Where(t => t.FullName.Contains("Controller")).ToList();
var nonControllerClasses = AllClasses.FromLoadedAssemblies()
    .Where(t => !t.FullName.Contains("Controller")).ToList();

container.RegisterTypes(controllerClasses, WithMappings.FromMatchingInterface, WithName.Default);
container.RegisterTypes(nonControllerClasses, WithMappings.FromMatchingInterface, WithName.Default,
    type => new ContainerControlledLifetimeManager());

ПРИМЕЧАНИЕ. - Вы захотите создать выражения where в коде, который заполняет controllerClasses иnonControllerClasses более конкретно, так что вы регистрируете только те классы, которые вам нужны.IE фильтр по пространству имен.

...