统一决心的表现和使用

本文关键字:决心 | 更新日期: 2023-09-27 18:24:04

我们使用Unity作为我们的IOC容器。

到目前为止,我们编写程序的方式是在需要使用接口之前解析接口

然而,这会导致接口在循环中被解析。这可能导致接口在一次运行中被解析100000次。

问题是:将解决方案转移到循环之外会有显著差异吗?还是这只是微观优化?

我们的进步需要一天的时间。因此,对于那些将回答"自己测试"的人来说,在这里提问实际上更快:)

统一决心的表现和使用

这取决于您注册接口的方式。您向哪个LifetimeManager注册了它
你的程序总是需要一个新实例吗?或者它可能是一个又一个相同的例子?

如果您需要相同的实例(Singleton),请使用ContainerControlledLifetimeManager:

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

如果你不在乎你得到了哪个实例(新的或旧的,由GC维护),你可以使用ExternallyControlledLifeTimeManager:

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

您还可以创建自己的LifetimeManager实现,以更好地满足您的需求。

看看这篇关于LifetimeManagers 的文章

这当然会影响性能。这在多大程度上取决于所构建对象的依赖关系图的复杂性,以及是否也构建了任何资源(如数据库连接等)。

正如Unity所说,它既不是最快的,也不是最慢的容器。只是一般水平。

服务定位(使用Resolve而不是构造函数注入)被许多人认为是一种反模式。原因是它很容易被滥用,而且它将依赖项隐藏为实现细节(而不是在构造函数中记录依赖项)。

我不太明白你在循环中解析100000次是什么意思。。。如果你真的想解决100000次问题,那么无论你是否在循环中解决,速度都是一样的。

我建议您检查是否可以重用已经解决的实例。。。

同样,除了你,没有人能判断你的速度问题是否是由容器引起的。我们不知道你在100000次迭代的循环中在做什么,如果<你在循环中花费的时间的1%。不要等一天,只运行1000次迭代,你就会看到。。。

此外,您不需要运行业务逻辑,只需实现一个类似的循环,只需在那里解析接口,就可以看到Unity对应用程序的影响有多大。

但无论如何,100000次解析在1天以上意味着每秒2次。。。这会产生效果,但不会那么戏剧性。。。我宁愿看看你可以在你的业务逻辑中优化什么,或者并行化你的循环。

此外,Unity并没有被誉为有史以来最快的集装箱(事实上恰恰相反);)你可以试试Autofac,它明显更快。。。

以下是IoC容器的一些性能基准测试。

我相信(或者我希望。

我做了一个非常天真的测试,其中解析结果慢了一个数量级,但并不慢。当然,这并没有考虑到容器中可能注册的其他内容,或者正在管理的实例的数量,或者正在实例化的内容,或者我遗漏的任何其他因素。IMHO真正回答你问题的唯一方法是测试你的应用程序,对不起:(

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{}

这个问题有点老了,但我发现在使用Unity时,为了提高性能,我强制使用了除Controllers之外的任何对象的singleton、ContainerControlledLifetimeManager实例(在上面的Roels答案中提到)。每次调用控制器时,它们都需要是新的实例。我在global.asax文件中调用的Bootstrap.cs/RegisterTypes方法中使用了以下代码。

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());

注意-您需要使填充controllerClass和nonControllerClass的代码中的where表达式更加具体,以便只注册所需的类。按命名空间筛选IE。