C# 懒散初始化器与懒惰<;T>;班级。什么时候使用每一个
和类之间有什么区别? 我知道它们都将仅在需要时初始化对象。 我什么时候需要使用它们C# 懒散初始化器与懒惰<;T>;班级。什么时候使用每一个,c#,C#,和类之间有什么区别? 我知道它们都将仅在需要时初始化对象。 我什么时候需要使用它们 `LazyInitializer` of an object means its object creation is deferred until it is ued first. 创建此窗体的对象是为了提高性能和减少内存浪费 而为了定义一个惰性初始化类型,我们使用Lazy初始化器类的Lazy(通用形式) E.g: Lazy<Orders> _orders = new Lazy<Orde
`LazyInitializer` of an object means its object creation is deferred until it is ued first.
创建此窗体的对象是为了提高性能和减少内存浪费
而为了定义一个惰性初始化类型,我们使用Lazy初始化器类的Lazy
(通用形式)
E.g:
Lazy<Orders> _orders = new Lazy<Orders>();
例如:
Lazy _orders=新的Lazy();
进一步参考:
懒散初始化器
允许您使用懒散初始化功能,而无需为每个懒散初始化的对象创建类
是懒散初始化器
可以提供的好处
使用Lazy
所产生的开销对于这种情况是否太大取决于您自己的要求。Lazy
()是一种通用包装器,它允许通过持有T
工厂方法(Func
)按需创建T
的实例并在访问属性getter时调用它
LazyInitializer
-带有一组静态方法的静态类,这只是一个使用(反射)来实例化给定类型实例的助手。它不保留任何本地私有字段,也不公开任何属性,因此不会产生内存使用开销
值得注意的是,这两个类都使用Func
作为实例工厂
关于LazyInitializer
类,只需简单几句话:
这些例程避免了需要分配专用的,
延迟初始化实例,而不是使用引用来确保
目标在访问时已初始化
附言:
我发现了一种有趣的方法,lazyinalizer
检查实例是否已经初始化,它只是将传入的引用与default(T)
进行比较,很好:
private static T EnsureInitializedCore<T>(ref T target, Func<T> valueFactory)
where T : class
{
T t = valueFactory();
if (t == null)
{
throw new InvalidOperationException(Environment.GetResourceString("Lazy_StaticInit_InvalidOperation"));
}
Interlocked.CompareExchange<T>(ref target, t, default(T));
return target;
}
关于惰性初始化的文档非常清楚地解释了这一点。看见简而言之,Lazy
为您使用的每个T
创建一个新类(构造的泛型),并为您标记的每个T
实例创建该类的新实例——即使底层T
从未初始化。使用LazyInitializer
的静态方法进行编码可能会更复杂,但可以避免Lazy
包装器实例的开销。我不确定您是否仍在研究这个问题,但最近我不得不深入研究Lazy
和LazyInitializer.EnsureInitialized()
的细节,所以我想我应该分享我的发现
首先,一些数字。我使用这两种方法对1000万个值的批次运行了基准测试,使用GC.GetTotalMemory(true)
测试内存使用情况,并获取实例化、首次值访问和后续值访问的Stopwatch
计时:
Lazy<T> Memory Use: 320,000,000 bytes (32B/instance)
EnsureInitialized<T>() Memory Use: N/A
Lazy<T> Instantiation Time: 622.01 ms
EnsureInitialized<T>() Inst. Time: N/A
Lazy<T> First Access: 1,373.50 ms
EnsureInitialized<T>() First Access: 72.94 ms
Lazy<T> Subsequent Accesses: 18.51 ms
EnsureInitialized<T>() Subsequent: 13.75 ms
惰性内存使用:320000000字节(32B/实例)
EnsureInitialized()内存使用:不适用
延迟实例化时间:622.01毫秒
EnsureInitialized()安装时间:不适用
延迟首次访问:1373.50毫秒
EnsureInitialized()首次访问:72.94毫秒
延迟后续访问:18.51毫秒
EnsureInitialized()后续:13.75毫秒
(我使用了LazyThreadSafetyMode.PublicationOnly
和Lazy的
,这看起来与默认情况下LazyInitializer
采用的线程安全方法相同。)
正如你所看到的,除非我以某种方式搞砸了我的测试(从来都不是不可能的!),否则在这种情况下,LazyInitializer
在几乎所有可量化的方面都是优越的。它没有内存或实例化开销,并且创建和检索值的速度更快
那么,您为什么要使用惰性
?首先,这些是在我的x64系统上的测试结果,在其他情况下可能会得到不同的结果
Lazy
还可以生成更清晰、更简洁的代码<代码>返回myLazy.Value代码>比返回LazyInitializer友好得多代码>
此外,Lazy
如果处理的是值类型,或者引用类型可以合法地为null
,则会使事情变得简单得多。使用LazyInitializer
,您必须使用第二个布尔字段来跟踪值是否已初始化,从而加剧了代码清晰度问题<如果您想要更严格的线程安全,代码>惰性
也更易于使用
从总体上看,对于许多应用程序来说,大部分开销可能可以忽略不计(虽然并非总是如此——我开始研究这一点的原因是因为我正在处理一个涉及数百万个非常小的延迟加载值的应用程序,而Lazy
的每个实例32字节的开销实际上开始变得不方便了)
最后,除非您的应用程序非常占用内存,否则我认为这通常是个人偏好的问题。对于非空引用类型,我个人认为LazyInitializer。EnsureInitialized()
是一种更优雅的方法,但我也可以挖掘代码清晰性参数。我认为这回答了您的问题:
LazyInitialization System.Threading.ThreadLocal的另一种方法
它与Lazy相同,但唯一的区别是它在线程本地存储数据。因此每个线程上的值将是初始化对象的不同副本
更多详情请参见:正如其他答案所说
Lazy
- 通常提供更干净的代码:只需使用
x=new Lazy(=>new…)初始化,并在访问它的任何地方使用x.Value
- 允许使用不同的预定义选项来处理初始化和异常(如果有多个线程)
Lazy<T> Memory Use: 320,000,000 bytes (32B/instance)
EnsureInitialized<T>() Memory Use: N/A
Lazy<T> Instantiation Time: 622.01 ms
EnsureInitialized<T>() Inst. Time: N/A
Lazy<T> First Access: 1,373.50 ms
EnsureInitialized<T>() First Access: 72.94 ms
Lazy<T> Subsequent Accesses: 18.51 ms
EnsureInitialized<T>() Subsequent: 13.75 ms