依赖注入带来的性能问题 [英] Performance problems from dependency injection
问题描述
在我的探查器报告中,我越来越看到带有依赖注入的基于模拟的测试的结果。许多依赖项是静态的,但是由于我们要单独测试方法,因此将它们更改为实例成员,例如以下示例:
In my profiler reports I'm increasingly seeing the results of mock-based testing with dependency injection. Many of the dependencies were static, but because we want to test methods in isolation they are changed to instance members, like the following example:
class ShortLivedThing {
IDependency1 dep1;
IDependency1 dep2;
IDependency1 dep3;
...
int TheRealData;
// Constructor used in production
public ShortLivedThing() {
dep1 = new Dep1(); dep2 = new Dep2(); dep3 = new Dep3();
}
// DI for testing
public ShortLivedThing(IDependency1 d1, IDependency2 d2, IDependency3 d3) {
dep1 = d1(); dep2 = d2(); dep3 = d3();
}
}
在大多数情况下,依赖关系又具有其他依赖关系等等。这导致每次 都实例化(主要是静态)对象树的树,方法调用是在测试之外进行的。每个对象都非常小(只有几个指针),但是树效应将其变成了性能不断提高的问题。
In turn the dependencies most of the time have other dependencies and so on. This results in the instantiation of a tree of (mostly "static") objects every time a method call is done outside of tests. Each of the objects are very small (just a few pointers), but the tree effect turns this into an ever increasing performance hit.
我们该怎么办? / p>
What can we do about it?
推荐答案
在我看来,您需要利用适当的依赖项注入框架可以为您提供的功能。不要对测试/生产使用不同的构造逻辑。
It seems to me like you need to leverage the features a proper dependency injection framework can give you. Do not use different construction logic for testing/production.
在春季,单例注入仅在容器启动时执行。每次都进行原型注射。每次进行单元测试(如果已进行布线)时,也会进行完整布线。因此,概要分析单元测试通常不是一个好主意。
With spring, singleton injections are only performed at container startup. Prototype injections are done every time. The full wiring is also done each time you run a unit test, if it's being wired. So profiling unit tests is generally not a good idea.
也许您使用的单例作用域太少,原型作用域又太多了? (原型=每次都有新实例)
Maybe you're using too little of the singleton scopes and too much prototype scope ? (Prototype = new instance every time)
弹簧注入的好处是您可以使用作用域代理,这意味着您的对象图看起来像这样:
The nice thing about spring injection is that you can use scope proxies, meaning your object graph can look like this:
A Singleton
|
B Singleton
|
C Prototype (per-invocation)
|
D Singleton
|
E Session scope (web app)
|
F Singleton
每个请求只会创建1个C实例和1个E实例每个会话。 A,B,D和F是单身人士。如果不是网络应用程序,则默认情况下没有会话范围,但您也可以设置自定义范围( Window范围对于带窗口的桌面应用程序来说很酷)。这里的线索是,您可以引入任何级别的作用域,有效地,您可以拥有十层单例对象,并且突然出现了会话作用域。 (这确实可以彻底改变您在分层体系结构中实现某些横切功能的方式,但这是另一回事)
And each request would only create 1 instance of C and one instance of E per session. A, B, D and F are singletons. If it's not a webapp you dont have session scope by default, but you can also make custom scopes (a "Window" scope sounds cool for a windowed desktop app). The clue here is that you can "introduce" scopes at any level, effectively you can have ten layers of singleton objects and all of a sudden something session scoped shows up. (This can really revolutionize how you implement some cross-cutting features in a layered architecture but that's a different story)
这确实使DI模型中的对象创建最少,我想。
This really gives the minimum object creation possible within a DI model, I think.
尽管这是Java的Spring,但我相信许多其他DI框架也应该支持类似的功能。也许不是最简约的。
Although this is Spring for Java I believe a number of other DI frameworks should support similar features. Maybe not the most minimalistic ones.
这篇关于依赖注入带来的性能问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!