统一决心的表现和使用
本文关键字:决心 | 更新日期: 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。