我们使用Unity作为我们的IOC容器。
到目前为止,我们的程序是以我们在需要使用它之前解析接口的方式编写的。
然而,这导致界面在循环内被解析。这可能导致界面在一次运行中被解决100,000次。
问题是:将解决方案移出循环会有显着差异,还是只是微优化?
我们的程序需要一天才能运行。所以对于那些会回答“自己测试”的人来说,问这里问题实际上更快:)
答案 0 :(得分:4)
这取决于你如何注册我想说的界面。使用LifetimeManager进行注册? 您的程序是否总是需要一个新实例?或者它可以一遍又一遍地是同一个实例?
如果您需要相同的实例(Singleton),请使用ContainerControlledLifetimeManager:
Container.RegisterType<Interface, Implementation>(new ContainerControlledLifetimeManager());
如果您不关心您获得的实例(新旧版本,由GC维护),您可以使用ExternallyControlledLifeTimeManager:
Container.RegisterType<Interface, Implementation>(new ExternallyControlledLifeTimeManager());
您还可以创建自己的LifetimeManager实现,以更好地满足您的需求。
请查看有关LifetimeManagers
的这篇文章答案 1 :(得分:1)
我确定(或者我希望!)已经优化了解决方案,特别是在容器控制的实例(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{}
答案 2 :(得分:1)
它当然会影响性能。多少取决于构造对象具有的依赖图的复杂性以及是否构造了任何资源(例如数据库连接等)。
正如Unity所说,它不是最快或最慢的容器。差不多平均。
服务地点(使用Resolve
而不是构造函数注入)被许多人视为反模式。原因是它很容易被滥用,并且它将依赖关系隐藏为实现细节(而不是在构造函数中记录依赖关系)。
答案 3 :(得分:1)
我不太明白你用循环解决100,000次是什么意思... 如果你想要解决100,000次,那么无论你是否在循环中进行,速度都是一样的。
我建议你检查一下你是否可以重用已经解决的实例......
同样,没有人,但你可以判断你的速度问题是否是由容器引起的。 我们不知道你在100,000次迭代的循环中做了什么,如果在循环本身内花费的时间是1%,那么解析接口的开销可能很有可能。不要等待一天,只需1000次迭代就可以运行它,你会看到......
此外,您不需要运行业务逻辑,只需实现类似的循环并仅在那里解析您的接口,这样您就可以看到Unity对您的应用程序有多大影响。
但无论如何,超过1天的100,000次结算意味着每秒约2次......这会产生影响,但不是那么戏剧性......我宁愿看看你的业务逻辑中可以优化的东西,还是你的竞争对手循环。
Unity也没有最快容器的声誉(事实上它完全相反);)你可以尝试Autofac,它明显更快......
答案 4 :(得分:0)
这个问题有点陈旧,但我发现在使用Unity时,为了提高性能,我强制使用除控制器之外的任何对象的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());
注意 - 您需要使填充controllerClasses和nonControllerClasses的代码上的where表达式更具体,以便您只注册所需的类。 IE按命名空间过滤。