dan*_*iax 312 .net c# lazy-evaluation
我发现这篇文章是关于Lazy:C#4.0中的懒惰 - 懒惰
使用Lazy对象获得最佳性能的最佳实践是什么?有人能指出我在实际应用中的实际用途吗?换句话说,我什么时候应该使用它?
Jam*_*are 229
当您想要在第一次实际使用时实例化某些内容时,通常会使用它.这延迟了创建它的成本,直到需要/何时需要而不是总是产生成本.
通常,当对象可能使用或不使用时,这是优选的,并且构建它的成本是非平凡的.
Mat*_*hew 119
你应该尽量避免使用Singletons,但如果你真的需要,Lazy<T>可以轻松实现懒惰,线程安全的单例:
public sealed class Singleton
{
// Because Singleton's constructor is private, we must explicitly
// give the Lazy<Singleton> a delegate for creating the Singleton.
static readonly Lazy<Singleton> instanceHolder =
new Lazy<Singleton>(() => new Singleton());
Singleton()
{
// Explicit private constructor to prevent default public constructor.
...
}
public static Singleton Instance => instanceHolder.Value;
}
Run Code Online (Sandbox Code Playgroud)
Des*_*tar 82
延迟加载派上用场的一个很好的现实示例是ORM(对象关系映射器),例如Entity Framework和NHibernate.
假设您有一个实体Customer,其中包含Name,PhoneNumber和Orders的属性.Name和PhoneNumber是常规字符串,但Orders是一个导航属性,它返回客户所做的每个订单的列表.
您经常可能想要查看所有客户的姓名和电话号码来打电话给他们.这是一个非常快速和简单的任务,但想象一下,如果每次创建一个客户,它会自动进行复杂的连接以返回数千个订单.最糟糕的是,你甚至不会使用订单,因此完全浪费资源!
这是延迟加载的最佳位置,因为如果Order属性是惰性的,除非您确实需要它,否则它不会获取所有客户的订单.您可以枚举Customer对象,只获取其名称和电话号码,同时Order属性耐心地休眠,随时为您准备好.
Ben*_*Ben 38
我一直在考虑使用Lazy<T>属性来帮助提高我自己的代码的性能(并学习更多关于它的信息).我来这里寻找关于何时使用它的答案,但似乎我去的每个地方都有这样的短语:
使用延迟初始化来推迟创建大型或资源密集型对象,或者执行资源密集型任务,尤其是在程序生命周期内可能不会发生此类创建或执行时.
我有点困惑,因为我不知道在哪里划线.例如,我认为线性插值是一个相当快速的计算,但如果我不需要这样做,那么懒惰初始化可以帮助我避免这样做并且值得吗?
最后我决定尝试自己的测试,我想我会在这里分享结果.不幸的是,我并不是真正做这类测试的专家,因此我很乐意收到有关改进的评论.
描述
对于我的情况,我特别感兴趣的是看看Lazy Properties是否可以帮助改进我的代码中进行大量插值(大部分未使用)的部分,因此我创建了一个比较3种方法的测试.
我为每种方法创建了一个单独的测试类,其中包含20个测试属性(让我们称之为t-properties).
测试结果以ms为单位测量,是50个实例或20个属性获得的平均值.然后每次测试运行5次.
测试1结果:实例化(平均50个实例化)
Run Code Online (Sandbox Code Playgroud)Class 1 2 3 4 5 Avg % ------------------------------------------------------------------------ GetInterp 0.005668 0.005722 0.006704 0.006652 0.005572 0.0060636 6.72 InitInterp 0.08481 0.084908 0.099328 0.098626 0.083774 0.0902892 100.00 InitLazy 0.058436 0.05891 0.068046 0.068108 0.060648 0.0628296 69.59
测试2结果:首先获得(平均20个属性获得)
Run Code Online (Sandbox Code Playgroud)Class 1 2 3 4 5 Avg % ------------------------------------------------------------------------ GetInterp 0.263 0.268725 0.31373 0.263745 0.279675 0.277775 54.38 InitInterp 0.16316 0.161845 0.18675 0.163535 0.173625 0.169783 33.24 InitLazy 0.46932 0.55299 0.54726 0.47878 0.505635 0.510797 100.00
测试3结果:第二次获得(平均20个属性获得)
Run Code Online (Sandbox Code Playgroud)Class 1 2 3 4 5 Avg % ------------------------------------------------------------------------ GetInterp 0.08184 0.129325 0.112035 0.097575 0.098695 0.103894 85.30 InitInterp 0.102755 0.128865 0.111335 0.10137 0.106045 0.110074 90.37 InitLazy 0.19603 0.105715 0.107975 0.10034 0.098935 0.121799 100.00
意见
GetInterp是最快的实例化,因为它没有做任何事情.InitLazy实例化比InitInterp设置延迟属性的开销比线性插值计算更快.但是,我在这里有点困惑,因为它InitInterp应该进行20次线性插值(设置它的t-属性),但实例化(测试1)只花费0.09 ms,相比之下只GetInterp需要0.28 ms进行一次线性插值第一次(测试2),第二次测试0.1毫秒(测试3).
它InitLazy比GetInterp第一次获取属性要花费近2倍,而InitInterp速度最快,因为它在实例化期间填充了它的属性.(至少这应该是它应该做的但为什么它的实例化结果比单个线性插值快得多?当它正在进行这些插值时?)
不幸的是,在我的测试中看起来有一些自动代码优化.它应该花费GetInterp相同的时间第一次获得属性,因为它第二次获得属性,但它显示的速度超过2倍.看起来这种优化也会影响其他类,因为它们都需要大约相同的时间用于测试3.但是,这样的优化也可能发生在我自己的生产代码中,这也可能是一个重要的考虑因素.
结论
虽然一些结果与预期一致,但也有一些非常有趣的意外结果可能是由于代码优化.即使对于看起来像在构造函数中执行大量工作的类,实例化结果也表明,与获取double属性相比,它们仍然可以非常快速地创建.虽然这个领域的专家可能能够更彻底地评论和调查,但我个人的感觉是,我需要再次进行此测试,但需要在我的生产代码上进行测试,以便检查那里可能会进行哪种优化.但是,我期待这InitInterp可能是要走的路.
Thu*_*kwa 14
只是指出Mathew发布的例子
public sealed class Singleton
{
// Because Singleton's constructor is private, we must explicitly
// give the Lazy<Singleton> a delegate for creating the Singleton.
private static readonly Lazy<Singleton> instanceHolder =
new Lazy<Singleton>(() => new Singleton());
private Singleton()
{
...
}
public static Singleton Instance
{
get { return instanceHolder.Value; }
}
}
Run Code Online (Sandbox Code Playgroud)
在懒惰出生之前,我们会这样做:
private static object lockingObject = new object();
public static LazySample InstanceCreation()
{
if(lazilyInitObject == null)
{
lock (lockingObject)
{
if(lazilyInitObject == null)
{
lazilyInitObject = new LazySample ();
}
}
}
return lazilyInitObject ;
}
Run Code Online (Sandbox Code Playgroud)
Vas*_*sea 12
来自MSDN:
使用Lazy实例来推迟创建大型或资源密集型对象或执行资源密集型任务,尤其是在程序生命周期内可能不会发生此类创建或执行时.
除了James Michael Hare的回答,Lazy还提供了线程安全的初始化.请查看LazyThreadSafetyMode枚举MSDN条目,该条目描述了此类的各种类型的线程安全模式.
| 归档时间: |
|
| 查看次数: |
120971 次 |
| 最近记录: |