【发布时间】:2018-01-10 11:24:39
【问题描述】:
我一直认为,在使用 Dagger2 时,如果我们不需要保证始终获得相同的实例,我们应该使用 @Reusable 范围而不是 @Singleton,因为 @Singleton 使用了双重检查,又贵又慢……
不过,我做了一个简单的性能测试,结果如下:
Reusable 4474 ms
Singleton 3603 ms
代码如下:
@Singleton
@Component
interface AppComponent {
fun getReusable(): ReusableFoo
fun getSingleton(): SingletonFoo
}
@Reusable
class ReusableFoo @Inject constructor()
@Singleton
class SingletonFoo @Inject constructor()
class TestClass {
@Test
fun test() {
val component = DaggerAppComponent.builder().build()
measure {
component.getReusable()
}
measure {
component.getSingleton()
}
}
private fun measure(block: () -> Unit) {
val start = System.currentTimeMillis()
(0..1000000000).forEach { block() }
println(System.currentTimeMillis() - start)
}
}
在构造较重的类(我尝试过使用Retrofit)和使用@Provide 注释方法而不是构造函数注入时出现同样的现象。
我是不是在测试中犯了一个错误,或者只是 @Reusable 比较慢?如果是这样,我们应该在哪里使用它?它比@Singleton 有什么好处吗?
【问题讨论】:
-
实际上,要构建一个 DCL 惯用语比普通的、非线程安全的惰性初始化惯用语要昂贵得多的场景实际上并不容易。唯一的区别是,使用 DCL,您总是必须从“内存”中获取,但在一个紧密的循环中,您只是到达 CPU 缓存。在一个紧密的循环之外,这两个习语可能都需要内存访问并且处于相同的基础上。
-
另一点:你已经测量了单例的 3.6 纳秒和可重用的 4.4 纳秒。那是 0.8 纳秒的差异,我敢打赌,有很多很多候选的微观级别的解释,所有这些都非常没有启发性。您真正的结论应该是“它根本没有区别”您使用哪个范围。或者你应该提出一个不同的基准来显示更明显的差异。
-
尝试颠倒您首先测试的顺序,如果它突然相反,我不会感到惊讶,也可能在这里查看微基准:stackoverflow.com/a/513259/1837367
-
@DavidMedenjak 我试过了;)但没有区别。感谢您提供此链接 - 回复非常有价值,尤其是其下方的一条评论:另外,除非您对 + 或 - 15 毫秒的准确度满意,否则切勿使用 System.currentTimeMillis()
标签: performance kotlin dagger-2